From e4da07b71dddb3b01b58ecaf21ae5b7052e98b7d Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期三, 26 八月 2020 16:01:01 +0800 Subject: [PATCH] 2020-08-26 --- src/menu/datasourcecomponent/verifycard/customscript/index.scss | 34 src/menu/actioncomponent/dragaction/index.scss | 6 src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss | 0 src/menu/datasourcecomponent/verifycard/customscript/index.jsx | 231 + src/tabviews/zshare/normalTable/index.jsx | 4 src/menu/actioncomponent/dragaction/index.jsx | 156 src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx | 150 src/templates/sharecomponent/chartcomponent/index.jsx | 5 src/menu/actioncomponent/verifyexcelin/customscript/index.jsx | 325 + src/menu/components/chart/antv-bar/index.scss | 199 - src/menu/datasourcecomponent/verifycard/settingform/index.scss | 24 src/templates/sharecomponent/tablecomponent/index.jsx | 4 src/menu/actioncomponent/verifyprint/index.jsx | 449 ++ src/menu/searchcomponent/index.jsx | 311 + src/menu/menushell/card.jsx | 6 src/views/menudesign/index.jsx | 58 src/menu/actioncomponent/verifyexcelin/index.jsx | 947 +++++ src/menu/actioncomponent/verifyexcelin/index.scss | 86 src/locales/zh-CN/mob.js | 1 src/menu/actioncomponent/dragaction/card.jsx | 56 src/menu/actioncomponent/actionform/index.scss | 33 src/menu/actioncomponent/verifyexcelout/columnform/index.jsx | 116 src/menu/searchcomponent/dategroup/index.scss | 38 src/menu/searchcomponent/dragsearch/card.jsx | 98 src/menu/searchcomponent/dategroup/index.jsx | 32 src/menu/datasourcecomponent/verifycard/settingform/utils.jsx | 84 src/menu/datasourcecomponent/verifycard/settingform/index.jsx | 352 ++ src/menu/actioncomponent/verifyexcelin/columnform/index.jsx | 221 + src/menu/actioncomponent/verifyexcelout/index.scss | 84 src/menu/menushell/index.scss | 31 src/menu/datasourcecomponent/index.scss | 94 src/menu/searchcomponent/dragsearch/index.scss | 6 src/menu/searchcomponent/searchform/index.scss | 32 src/menu/searchcomponent/index.scss | 78 src/menu/actioncomponent/index.scss | 93 src/menu/searchcomponent/searcheditable/index.scss | 43 src/menu/menuform/index.jsx | 4 src/menu/actioncomponent/actionform/index.jsx | 848 +++++ src/menu/actioncomponent/index.jsx | 969 +++++ src/menu/components/chart/antv-bar/index.jsx | 695 +++- src/menu/searchcomponent/dragsearch/index.jsx | 96 src/menu/actioncomponent/verifyprint/editable/index.jsx | 239 + src/menu/actioncomponent/verifyprint/index.scss | 68 src/menu/datasourcecomponent/index.jsx | 93 src/menu/actioncomponent/verifyprint/editable/index.scss | 51 src/menu/searchcomponent/searchform/index.jsx | 602 +++ src/menu/datasourcecomponent/verifycard/index.jsx | 551 +++ src/menu/datasourcecomponent/verifycard/index.scss | 81 src/menu/actioncomponent/verifyexcelin/customscript/index.scss | 0 src/menu/actioncomponent/verifyexcelout/columnform/index.scss | 0 src/menu/actioncomponent/verifyexcelout/index.jsx | 602 +++ src/menu/actioncomponent/verifyexcelin/columnform/index.scss | 0 src/menu/datasourcecomponent/verifycard/columnform/index.jsx | 145 src/menu/datasourcecomponent/verifycard/columnform/index.scss | 0 src/menu/datasourcecomponent/verifycard/utils.jsx | 111 src/menu/menushell/index.jsx | 3 src/menu/searchcomponent/searcheditable/index.jsx | 307 + src/locales/en-US/mob.js | 1 58 files changed, 9,561 insertions(+), 392 deletions(-) diff --git a/src/locales/en-US/mob.js b/src/locales/en-US/mob.js index 3b12865..ff4d6b0 100644 --- a/src/locales/en-US/mob.js +++ b/src/locales/en-US/mob.js @@ -10,6 +10,7 @@ 'mob.enable': '鍚�', 'mob.disable': '鍋�', 'mob.save': '淇濆瓨', + 'mob.style': 'Style', 'mob.menu': '鑿滃崟', 'mob.menu.first': '涓�绾�', 'mob.menu.second': '浜岀骇', diff --git a/src/locales/zh-CN/mob.js b/src/locales/zh-CN/mob.js index 3b12865..39f2fff 100644 --- a/src/locales/zh-CN/mob.js +++ b/src/locales/zh-CN/mob.js @@ -10,6 +10,7 @@ 'mob.enable': '鍚�', 'mob.disable': '鍋�', 'mob.save': '淇濆瓨', + 'mob.style': '鏍峰紡', 'mob.menu': '鑿滃崟', 'mob.menu.first': '涓�绾�', 'mob.menu.second': '浜岀骇', diff --git a/src/menu/actioncomponent/actionform/index.jsx b/src/menu/actioncomponent/actionform/index.jsx new file mode 100644 index 0000000..e159cec --- /dev/null +++ b/src/menu/actioncomponent/actionform/index.jsx @@ -0,0 +1,848 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Cascader } from 'antd' +import { btnIcons, btnClasses, formRule } from '@/utils/option.js' + +import Api from '@/api' +import options from '@/store/options.js' +import Utils from '@/utils/utils.js' +import './index.scss' + +const { TextArea } = Input + +class MainSearch extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + setting: PropTypes.object, // 椤甸潰璁剧疆 + formlist: PropTypes.any, // 琛ㄥ崟淇℃伅 + card: PropTypes.any, // 鎸夐挳淇℃伅 + tabs: PropTypes.array, // 鎵�鏈夋爣绛鹃〉 + inputSubmit: PropTypes.any // 鍥炶溅鎻愪氦浜嬩欢 + } + + state = { + formlist: null, // 琛ㄥ崟淇℃伅 + openType: null, // 鎵撳紑鏂瑰紡 + interType: null, // 鎺ュ彛绫诲瀷锛氬唴閮ㄣ�佸閮� + funcType: null, // 鍔熻兘绫诲瀷 + position: null, // 鎸夐挳浣嶇疆 + requireOptions: [{ + value: 'notRequired', + text: this.props.dict['header.form.notRequired'] + }, { + value: 'requiredSgl', + text: this.props.dict['header.form.requiredSgl'] + }, { + value: 'required', + text: this.props.dict['header.form.required'] + }, { + value: 'requiredOnce', + text: this.props.dict['header.form.requiredOnce'] + }], + insertUpdateOptions: [{ + value: '', + text: this.props.dict['model.empty'] + }, { + value: 'insert', + text: this.props.dict['header.form.action.insert'] + }, { + value: 'update', + text: this.props.dict['header.form.action.update'] + }, { + value: 'audit', + text: this.props.dict['header.form.action.audit'] + }], + deleteOptions: [{ + value: '', + text: this.props.dict['model.empty'] + }, { + value: 'LogicDelete', + text: this.props.dict['header.form.action.LogicDelete'] + }, { + value: 'delete', + text: this.props.dict['header.form.action.delete'] + }, { + value: 'custom', + text: this.props.dict['header.form.custom'] + }] + } + + + UNSAFE_componentWillMount () { + const { card } = this.props + + let _menulist = this.props.formlist.filter(form => form.key === 'linkmenu')[0] || '' + let _opentype = card.OpenType // 鎵撳紑鏂瑰紡 + let _tabType = card.tabType || 'SubTable' // 鎸夐挳涓哄脊绐楋紙鏍囩锛夋椂锛屾爣绛剧殑绫诲瀷 + let _options = null // 閫夐」鍒楄〃 + + if (card.execMode) { // 杞崲鎵撳嵃鏃舵墦寮�鏂瑰紡 + _opentype = 'funcbutton' + } else if (_opentype === 'outerpage') { + card.pageTemplate = 'custom' + _opentype = 'innerpage' + } + + let _tabs = this.props.tabs.filter(tab => tab.type === _tabType) + + if (_opentype === 'innerpage') { // 鏂伴〉闈紝鍙�夋ā鏉�(鑷畾涔夋椂锛屽彲濉叆澶栭儴閾炬帴) + _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position'] + if (card.pageTemplate === 'custom') { + _options.push('url', 'joint') + } + } else if (_opentype === 'blank' || _opentype === 'tab') { // 鏂版爣绛炬垨褰撳墠椤甸潰鏇挎崲 + _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate'] + if (card.tabTemplate === 'ThdMenu') { + _options.push('linkmenu') + } + } else if (_opentype === 'popview') { // 妯℃�佹鏍囩椤� + _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose'] + } else if (_opentype === 'excelOut') { // 瀵煎叆瀵煎嚭 + if (card.intertype === 'outer') { + _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'] + } else { + _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'] + } + } else if (_opentype === 'excelIn') { // 瀵煎叆瀵煎嚭 + if (card.intertype === 'outer') { + _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError'] + } else { + _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError'] + } + } else if (_opentype === 'funcbutton') { + if (!card.funcType) { + _options = ['label', 'OpenType', 'funcType', 'icon', 'class'] + } else if (card.funcType === 'changeuser') { + _options = ['label', 'OpenType', 'funcType', 'icon', 'class'] + } else if (card.funcType === 'print') { + if (card.intertype === 'outer') { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } else { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } + } + } else { + if (card.intertype === 'outer') { + _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } else { + _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType'] + } + } + this.setState({ + openType: _opentype, + menulist: _menulist.options || [], + interType: card.intertype || 'inner', + position: card.position || 'toolbar', + funcType: card.funcType, + formlist: this.props.formlist.map(item => { + if (item.key === 'class') { + item.options = btnClasses + } else if (item.key === 'icon') { + item.options = btnIcons + } else if (item.key === 'Ot') { + if (card.position === 'grid' || card.pageTemplate === 'pay') { // 琛岀骇鎸夐挳銆佹敮浠樻寜閽紝鍙兘閫夊崟琛� + item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) + } else if (['innerpage', 'blank', 'tab', 'popview', 'excelIn'].includes(_opentype)) { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) + } else if (card.sqlType === 'insert') { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value)) + } else { + item.options = this.state.requireOptions + } + } else if (item.key === 'sqlType') { + if (['prompt', 'exec'].includes(_opentype)) { + item.options = this.state.deleteOptions + } else { + item.options = this.state.insertUpdateOptions + } + } else if (item.key === 'linkTab') { + item.options = [ + { + value: '', + text: '鏂板缓' + }, + ..._tabs + ] + } else if (item.key === 'OpenType') { + item.initVal = _opentype + } + + item.hidden = !_options.includes(item.key) + return item + }) + }) + } + + componentDidMount () { + const { card } = this.props + + if (card.focus) { + try { + let _form = document.getElementById('label') + _form.select() + } catch { + console.warn('琛ㄥ崟focus澶辫触锛�') + } + } + } + + /** + * @description 涓嬫媺鍒囨崲 + * 1銆佹墦寮�鏂瑰紡鍒囨崲锛岄噸缃彲瑙佽〃鍗曞拰琛ㄥ崟鍊� + * 2銆佹樉绀轰綅缃垏鎹紝閲嶇疆閫夋嫨琛� + * 3銆佸垏鎹㈡爣绛剧被鍨嬶紝閲嶇疆鍙�夋爣绛� + */ + openTypeChange = (key, value) => { + const { card } = this.props + + if (key === 'OpenType') { + let _options = null + if (value === 'innerpage') { + _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position'] + if (card.pageTemplate === 'custom') { + _options.push('url', 'joint') + } + } else if (value === 'blank' || value === 'tab') { + _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate'] + if (card.tabTemplate === 'ThdMenu') { + _options.push('linkmenu') + } + } else if (value === 'popview') { + _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose'] + } else if (value === 'excelOut') { + if (this.state.interType === 'outer') { + _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'] + } else { + _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'] + } + } else if (value === 'excelIn') { + if (this.state.interType === 'outer') { + _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError'] + } else { + _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError'] + } + } else if (value === 'funcbutton') { + if (!this.state.funcType) { + _options = ['label', 'OpenType', 'funcType', 'icon', 'class'] + } else if (this.state.funcType === 'changeuser') { + _options = ['label', 'OpenType', 'funcType', 'icon', 'class'] + } else if (this.state.funcType === 'print') { + if (this.state.interType === 'outer') { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } else { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } + } + } else { + if (this.state.interType === 'inner') { + _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType'] + } else { + _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc'] + } + } + + let _fieldval = {} + + let _formlist = this.state.formlist.map(item => { + item.hidden = !_options.includes(item.key) + + if (item.hidden) return item + + if (item.key === 'intertype') { + _fieldval.intertype = this.state.interType + } else if (item.key === 'Ot') { + if (this.state.position === 'grid') { + item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) + _fieldval.Ot = 'requiredSgl' + } else if (['innerpage', 'blank', 'tab', 'popview'].includes(value)) { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) + _fieldval.Ot = 'requiredSgl' + } else if (value === 'excelIn') { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) + _fieldval.Ot = 'notRequired' + } else { + item.options = this.state.requireOptions + } + } else if (item.key === 'sqlType') { + if (['prompt', 'exec'].includes(value)) { + item.options = this.state.deleteOptions + } else { + item.options = this.state.insertUpdateOptions + } + _fieldval.sqlType = '' + } + + return item + }) + + this.setState({ + openType: value, + formlist: _formlist + }, () => { + if (value === 'excelIn') { + _fieldval.label = this.props.dict['model.form.excelIn'] + _fieldval.class = 'border-dgreen' + } else if (value === 'excelOut') { + _fieldval.label = this.props.dict['model.form.excelOut'] + _fieldval.class = 'dgreen' + } + + this.props.form.setFieldsValue(_fieldval) + }) + } else if (key === 'position') { + let _fieldval = {} + + this.setState({ + position: value, + formlist: this.state.formlist.map(item => { + if (item.key === 'Ot') { + if (value === 'grid') { + item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) + _fieldval.Ot = 'requiredSgl' + } else if (['innerpage', 'blank', 'tab', 'popview'].includes(this.state.openType)) { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) + _fieldval.Ot = 'requiredSgl' + } else { + item.options = this.state.requireOptions + } + } + return item + }) + }, () => { + this.props.form.setFieldsValue(_fieldval) + }) + } else if (key === 'tabType') { + let _tabs = this.props.tabs.filter(tab => tab.type === value) + let _fieldval = {} + + this.setState({ + formlist: this.state.formlist.map(item => { + if (item.key === 'linkTab') { + item.options = [ + { + value: '', + text: '鏂板缓' + }, + ..._tabs + ] + } + return item + }) + }, () => { + this.props.form.setFieldsValue(_fieldval) + }) + } else if (key === 'funcType') { + let _options = null + if (!value) { + _options = ['label', 'OpenType', 'funcType', 'icon', 'class'] + } else if (value === 'changeuser') { + _options = ['label', 'OpenType', 'funcType', 'icon', 'class'] + } else if (value === 'print') { + if (this.state.interType === 'outer') { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } else { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } + } + let _fieldval = {} + + this.setState({ + formlist: this.state.formlist.map(item => { + item.hidden = !_options.includes(item.key) + + if (item.hidden) return item + + if (item.key === 'intertype') { + _fieldval.intertype = this.state.interType + } else if (item.key === 'Ot' && value === 'print') { + item.options = this.state.requireOptions + } + + return item + }) + }, () => { + this.props.form.setFieldsValue(_fieldval) + }) + } else if (key === 'sqlType') { + let _fieldval = {} + this.setState({ + formlist: this.state.formlist.map(item => { + if (item.key === 'Ot' && value === 'insert') { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value)) + } else if (item.key === 'Ot') { + item.options = this.state.requireOptions + } + return item + }) + }, () => { + if (value === 'insert') { + _fieldval.label = '娣诲姞' + _fieldval.class = 'green' + _fieldval.Ot = 'notRequired' + } else if (value === 'update') { + _fieldval.label = '淇敼' + _fieldval.class = 'purple' + _fieldval.Ot = 'requiredSgl' + } else if (value === 'audit') { + _fieldval.label = '瀹℃牳' + _fieldval.class = 'purple' + _fieldval.Ot = 'requiredSgl' + } else if (value === 'LogicDelete' || value === 'delete') { + _fieldval.label = '鍒犻櫎' + _fieldval.class = 'danger' + _fieldval.Ot = 'required' + } + + this.props.form.setFieldsValue(_fieldval) + }) + } else if (key === 'pageTemplate') { + let _options = null + let _fieldval = {} + if (value === 'custom') { + _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'url', 'joint', 'icon', 'class', 'position'] + } else { + _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position'] + } + + this.setState({ + openType: value, + formlist: this.state.formlist.map(item => { + item.hidden = !_options.includes(item.key) + + if (item.key === 'Ot') { + if (value === 'pay') { + item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) + _fieldval.Ot = 'requiredSgl' + } else { + item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) + } + } + + return item + }) + }, () => { + this.props.form.setFieldsValue(_fieldval) + }) + } else if (key === 'tabTemplate') { + let _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate'] + + if (value === 'ThdMenu') { + _options.push('linkmenu') + } + + this.setState({ + openType: value, + formlist: this.state.formlist.map(item => { + item.hidden = !_options.includes(item.key) + + return item + }) + }) + } + } + + onChange = (e, key) => { + const { openType } = this.state + let value = e.target.value + + if (key === 'intertype') { + let _options = null + if (openType === 'excelOut') { + if (value === 'outer') { + _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'] + } else { + _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'] + } + } else if (openType === 'excelIn') { + if (value === 'outer') { + _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError'] + } else { + _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError'] + } + } else if (openType === 'funcbutton') { + if (value === 'outer') { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } else { + _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError'] + } + } else { + if (value === 'inner') { + _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType'] + } else { + _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc'] + } + } + + this.setState({ + interType: value, + formlist: this.state.formlist.map(item => { + item.hidden = !_options.includes(item.key) + + if (item.key === 'interface') { + item.readonly = false + } else if (item.key === 'sysInterface') { + item.initVal = 'false' + } else if (item.key === 'Ot') { + item.options = this.state.requireOptions + } + return item + }) + }, () => { + if (this.props.form.getFieldValue('sqlType') !== undefined) { + this.props.form.setFieldsValue({sqlType: ''}) + } + }) + } else if (key === 'sysInterface') { + if (value === 'true') { + this.props.form.setFieldsValue({ + interface: window.GLOB.mainSystemApi || '' + }) + } + this.setState({ + formlist: this.state.formlist.map(item => { + if (item.key === 'interface' && value === 'true') { + item.readonly = true + } else if (item.key === 'interface') { + item.readonly = false + } + + return item + }) + }) + } + } + + handleSubmit = (e) => { + e.preventDefault() + + if (this.props.inputSubmit) { + this.props.inputSubmit() + } + } + + getFields() { + const { getFieldDecorator } = this.props.form + const fields = [] + + this.state.formlist.forEach((item, index) => { + if (item.hidden) return + + if (item.type === 'text') { // 鏂囨湰鎼滅储 + let _rules = [] + if (item.key === 'innerFunc') { + let str = '^(' + item.fields.join('|') + ')' + let _patten = new RegExp(str + formRule.func.innerPattern + '$', 'g') + _rules = [{ + pattern: _patten, + message: formRule.func.innerMessage + }, { + max: formRule.func.max, + message: formRule.func.maxMessage + }] + } else if (item.key === 'outerFunc' || item.key === 'callbackFunc') { + _rules = [{ + pattern: formRule.func.pattern, + message: formRule.func.message + }, { + max: formRule.func.max, + message: formRule.func.maxMessage + }] + } else { + _rules = [{ + max: formRule.input.max, + message: formRule.input.message + }] + } + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.tooltip ? + <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}> + <Icon type="question-circle" /> + {item.label} + </Tooltip> : item.label + }> + {getFieldDecorator(item.key, { + initialValue: item.initVal || '', + rules: [ + { + required: item.readonly ? false : !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + }, + ..._rules + ] + })(<Input 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" overlayClassName={item.tooltipClass} title={item.tooltip}> + <Icon type="question-circle" /> + {item.label} + </Tooltip> : item.label + }> + {getFieldDecorator(item.key, { + initialValue: item.initVal, + rules: [ + { + required: item.readonly ? false : !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + } + ] + })(<InputNumber min={0} max={10000} precision={0} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'select') { // 涓嬫媺鎼滅储 + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.tooltip ? + <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} 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 + '!' + } + ] + })( + <Select + showSearch + filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0} + onChange={(value) => {this.openTypeChange(item.key, value)}} + getPopupContainer={() => document.getElementById('winter')} + > + {item.options.map((option, index) => + <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}> + {item.key === 'icon' && option.value && <Icon type={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.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.onChange(e, item.key)}} disabled={item.readonly}> + { + item.options.map(option => { + return ( + <Radio key={option.value} value={option.value}>{option.text}</Radio> + ) + }) + } + </Radio.Group> + )} + </Form.Item> + </Col> + ) + } else if (item.type === 'textarea') { + fields.push( + <Col span={24} key={index}> + <Form.Item label={item.label} className="textarea"> + {getFieldDecorator(item.key, { + initialValue: item.initVal + })(<TextArea rows={4} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'cascader') { // 澶氶�� + 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 + '!' + } + ] + })( + <Cascader + options={this.state.menulist} + loadData={this.loadData} + placeholder="" + /> + )} + </Form.Item> + </Col> + ) + } + }) + return fields + } + + loadData = selectedOptions => { + const { MenuID } = this.props + const targetOption = selectedOptions[selectedOptions.length - 1] + targetOption.loading = true + + let _param = { + func: 'sPC_Get_FunMenu', + ParentID: targetOption.value, + systemType: options.sysType, + debug: 'Y' + } + + Api.getSystemConfig(_param).then(result => { + if (result.status) { + targetOption.loading = false + targetOption.children = result.data.map(item => { + let submenu = { + value: item.ParentID, + label: item.MenuNameP, + children: item.FunMenu.map(cell => { + return { + value: cell.MenuID, + label: cell.MenuName, + MenuID: cell.MenuID, + MenuName: cell.MenuName, + MenuNo: cell.MenuNo, + Ot: cell.Ot, + PageParam: cell.PageParam, + LinkUrl: cell.LinkUrl, + disabled: cell.MenuID === MenuID + } + }) + } + + return submenu + }) + + this.setState({ + menulist: [...this.state.menulist] + }) + } else { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + targetOption.loading = false + } + }) + } + + handleConfirm = () => { + const { setting } = this.props + const { menulist } = this.state + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.props.card.uuid + values.verify = this.props.card.verify || null + + if (values.OpenType === 'excelIn') { + values.position = 'toolbar' + } else if (values.OpenType === 'excelOut') { + if (values.intertype === 'inner' && !values.innerFunc) { + if ((setting.interType === 'inner' && setting.innerFunc) || setting.interType === 'outer') { + notification.warning({ + top: 92, + message: '琛ㄦ牸鏁版嵁鏌ヨ鏈娇鐢ㄦ暟鎹簮锛屽鍑篍xcel浣跨敤鍐呴儴鎺ュ彛鏃讹紝闇�鑷畾涔夊唴閮ㄥ嚱鏁帮紒', + duration: 5 + }) + return + } + } + + values.position = 'toolbar' + values.Ot = 'notRequired' + } else if (values.OpenType === 'popview' && !values.linkTab) { // 娌℃湁鍏宠仈鏍囩锛堟柊寤烘椂锛夛紝鍒涘缓鏂版爣绛綢d + values.linkTab = Utils.getuuid() + values.createTab = true // 鐢ㄤ簬鏍囪鎸夐挳澶嶅埗鏃讹紝鏄惁澶嶅埗鍘熸湁鏍囩 + } else if (values.OpenType === 'funcbutton') { // 杞崲鎵撳嵃鏃舵墦寮�鏂瑰紡 + values.position = 'toolbar' + if (values.funcType === 'print') { + values.OpenType = values.execMode + } + } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) { + if (values.Ot === 'requiredOnce' && ['notRequired', 'requiredSgl', 'required'].includes(this.props.card.Ot)) { + values.verify.uniques = [] + } else if (this.props.card.Ot === 'requiredOnce' && ['notRequired', 'requiredSgl', 'required'].includes(values.Ot)) { + values.verify.uniques = [] + } + } + + // 鍏宠仈涓夌骇鑿滃崟 + if (values.OpenType === 'tab' && values.linkmenu && values.linkmenu.length > 0) { + let linkThdMenu = '' + menulist.forEach(menu => { + if (menu.value === values.linkmenu[0]) { + menu.children.forEach(item => { + if (item.value === values.linkmenu[1]) { + item.children.forEach(cell => { + if (cell.value === values.linkmenu[2]) { + linkThdMenu = cell + } + }) + } + }) + } + }) + values.linkThdMenu = linkThdMenu + } + + if (values.innerFunc === '' && values.sql === '') { + notification.warning({ + top: 92, + message: this.props.dict['header.form.actionhelp.tablename'], + duration: 5 + }) + } else if (values.innerFunc === '' && values.sql !== '' && values.sqlType === '') { + notification.warning({ + top: 92, + message: this.props.dict['header.form.actionhelp.sqlType'], + duration: 5 + }) + } else { + resolve(values) + } + } else { + reject(err) + } + }) + }) + } + + render() { + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 7 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 17 } + } + } + return ( + <Form {...formItemLayout} className="ant-advanced-search-form commontable-action-form" id="winter"> + <Row gutter={24}>{this.getFields()}</Row> + </Form> + ) + } +} + +export default Form.create()(MainSearch) \ No newline at end of file diff --git a/src/menu/actioncomponent/actionform/index.scss b/src/menu/actioncomponent/actionform/index.scss new file mode 100644 index 0000000..c25cef2 --- /dev/null +++ b/src/menu/actioncomponent/actionform/index.scss @@ -0,0 +1,33 @@ +.ant-advanced-search-form.commontable-action-form { + min-height: 190px; + .superconfig { + color: #1890ff; + cursor: pointer; + } + .textarea { + .ant-col-sm-7 { + width: 14%; + } + .ant-col-sm-17 { + width: 86%; + } + } + .ant-input-number { + width: 100%; + } + .anticon-question-circle { + color: #c49f47; + position: relative; + left: -3px; + } + .with-button { + .ant-form-item-control-wrapper { + padding-right: 63px; + } + .ant-btn { + position: absolute; + right: 12px; + top: 4.5px; + } + } +} \ No newline at end of file diff --git a/src/menu/actioncomponent/dragaction/card.jsx b/src/menu/actioncomponent/dragaction/card.jsx new file mode 100644 index 0000000..670a8c5 --- /dev/null +++ b/src/menu/actioncomponent/dragaction/card.jsx @@ -0,0 +1,56 @@ +import React from 'react' +import { useDrag, useDrop } from 'react-dnd' +import { Icon, Button } from 'antd' +import './index.scss' + +const Card = ({ id, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, doubleClickCard }) => { + const originalIndex = findCard(id).index + const [{ isDragging }, drag] = useDrag({ + item: { type: 'action', id, originalIndex }, + collect: monitor => ({ + isDragging: monitor.isDragging(), + }), + }) + const [, drop] = useDrop({ + accept: 'action', + canDrop: () => true, + drop: () => {}, + hover({ id: draggedId }) { + if (!draggedId) return + if (draggedId !== id) { + const { index: overIndex } = findCard(id) + moveCard(draggedId, overIndex) + } + }, + }) + const opacity = isDragging ? 0 : 1 + + let hasProfile = false + if (['pop', 'prompt', 'exec'].includes(card.OpenType)) { + hasProfile = true + } else if (card.OpenType === 'excelIn' || card.OpenType === 'excelOut') { + hasProfile = true + } else if (card.funcType === 'print') { + hasProfile = true + } + + return ( + <div className="page-card" style={{ opacity: opacity}}> + <div ref={node => drag(drop(node))}> + <Button + className={'mk-btn mk-' + card.class} + icon={card.icon} + key={card.uuid} + onDoubleClick={() => doubleClickCard(id)} + > + {card.label}{card.position === 'grid' && <Icon type="table" />} + </Button> + </div> + <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} /> + <Icon className="edit copy" title="copy" type="copy" onClick={() => copyCard(id)} /> + <Icon className="edit close" title="close" type="close" onClick={() => delCard(id)} /> + {hasProfile ? <Icon className="edit profile" title="setting" type="profile" onClick={() => profileCard(id)} /> : null} + </div> + ) +} +export default Card diff --git a/src/menu/actioncomponent/dragaction/index.jsx b/src/menu/actioncomponent/dragaction/index.jsx new file mode 100644 index 0000000..5f310c0 --- /dev/null +++ b/src/menu/actioncomponent/dragaction/index.jsx @@ -0,0 +1,156 @@ +import React, { useState } from 'react' +import { useDrop } from 'react-dnd' +import { is, fromJS } from 'immutable' +import update from 'immutability-helper' +import { Icon } from 'antd' + +import Utils from '@/utils/utils.js' +import Card from './card' +import './index.scss' + +const Container = ({list, handleList, handleMenu, deleteMenu, profileMenu, doubleClickCard }) => { + const [cards, setCards] = useState(list) + const moveCard = (id, atIndex) => { + const { card, index } = findCard(id) + const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] }) + handleList(_cards) + } + + if (!is(fromJS(cards), fromJS(list))) { + setCards(list) + } + + const findCard = id => { + const card = cards.filter(c => `${c.uuid}` === id)[0] + return { + card, + index: cards.indexOf(card), + } + } + + const doubleClickBtn = id => { + const { card } = findCard(id) + doubleClickCard(card) + } + + const editCard = id => { + const { card } = findCard(id) + handleMenu(card) + } + + const profileCard = id => { + const { card } = findCard(id) + profileMenu(card) + } + + const delCard = id => { + const { card } = findCard(id) + deleteMenu(card) + } + + const copyCard = id => { + const { card } = findCard(id) + let copycard = fromJS(card).toJS() + + copycard.uuid = Utils.getuuid() + copycard.origin = false + copycard.copyType = 'action' + copycard.label = copycard.label + '(copy)' + copycard.focus = true + + copycard.originCard = card + + if (copycard.OpenType === 'popview') { // 寰呭畬鍠� + copycard.linkTab = '' + } + + let _val = fromJS(copycard).toJS() + + try { + _val.uuid = Utils.getuuid() + _val = window.btoa(window.encodeURIComponent(JSON.stringify(_val))) + } catch { + console.warn('Stringify Failure') + _val = '' + } + + if (_val) { + let oInput = document.createElement('input') + oInput.value = _val + document.body.appendChild(oInput) + oInput.select() + document.execCommand('Copy') + document.body.removeChild(oInput) + } + + const { index: overIndex } = findCard(id) + + const _cards = update(cards, { $splice: [[overIndex + 1, 0, copycard]] }) + + handleList(_cards, copycard) + } + + const [, drop] = useDrop({ + accept: 'action', + drop(item) { + if (item.hasOwnProperty('originalIndex')) { + return + } + } + }) + + const addaction = () => { + let newcard = {} + newcard.uuid = Utils.getuuid() + newcard.focus = true + + newcard.label = 'button' + newcard.sqlType = '' + newcard.Ot = 'requiredSgl' + newcard.OpenType = 'excelIn' + newcard.tabType = 'SubTable' + newcard.icon = '' + newcard.class = 'default' + newcard.intertype = 'inner' + newcard.method = 'POST' + newcard.position = 'toolbar' + newcard.execSuccess = 'grid' + newcard.execError = 'never' + newcard.popClose = 'never' + newcard.errorTime = 10 + newcard.verify = null + + let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0 + + const { index: overIndex } = findCard(`${targetId}`) + let targetIndex = overIndex + + targetIndex++ + + const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] }) + + handleList(_cards, newcard) + } + + return ( + <div ref={drop} className="ant-row"> + {cards.map(card => ( + <Card + id={card.uuid} + key={card.uuid} + card={card} + moveCard={moveCard} + copyCard={copyCard} + editCard={editCard} + delCard={delCard} + findCard={findCard} + profileCard={profileCard} + doubleClickCard={doubleClickBtn} + /> + ))} + + <Icon type="plus" onClick={addaction}/> + </div> + ) +} +export default Container diff --git a/src/menu/actioncomponent/dragaction/index.scss b/src/menu/actioncomponent/dragaction/index.scss new file mode 100644 index 0000000..369ae98 --- /dev/null +++ b/src/menu/actioncomponent/dragaction/index.scss @@ -0,0 +1,6 @@ +.common-drawarea-placeholder { + width: 100%; + line-height: 65px; + text-align: center; + color: #bcbcbc; +} \ No newline at end of file diff --git a/src/menu/actioncomponent/index.jsx b/src/menu/actioncomponent/index.jsx new file mode 100644 index 0000000..5776ff9 --- /dev/null +++ b/src/menu/actioncomponent/index.jsx @@ -0,0 +1,969 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { Modal, notification, Button } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import options from '@/store/options.js' +import Utils from '@/utils/utils.js' +import DevUtils from '@/utils/devutils.js' +import zhCN from '@/locales/zh-CN/model.js' +import enUS from '@/locales/en-US/model.js' +import { getActionForm } from '@/templates/zshare/formconfig' + +import ActionForm from './actionform' +import VerifyCard from '@/templates/zshare/verifycard' +import CreateFunc from '@/templates/zshare/createfunc' +import VerifyPrint from './verifyprint' +import VerifyExcelIn from './verifyexcelin' +import VerifyExcelOut from './verifyexcelout' +import DragElement from './dragaction' +import './index.scss' + +const { confirm } = Modal + +class ActionComponent extends Component { + static propTpyes = { + type: PropTypes.string, // 鑿滃崟绫诲瀷锛屼富琛ㄦ垨瀛愯〃 + menu: PropTypes.object, // 鑿滃崟淇℃伅锛堣彍鍗昳d锛岃彍鍗曞弬鏁帮紝鑿滃崟鍚嶇О锛� + config: PropTypes.object, // 鑿滃崟閰嶇疆淇℃伅 + usefulFields: PropTypes.array, // 鑷畾涔夊嚱鏁板彲鐢ㄥ瓧娈� + tabs: PropTypes.array, // 鎵�鏈夋爣绛� + setSubConfig: PropTypes.func, // 璁剧疆瀛愰厤缃俊鎭� + updateaction: PropTypes.func // 鑿滃崟閰嶇疆鏇存柊 + } + + state = { + dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + card: null, // 缂栬緫涓厓绱� + formlist: null, // 琛ㄥ崟淇℃伅 + actionlist: null, // 鎸夐挳缁� + copying: false, // 鎸夐挳澶嶅埗涓� + visible: false, // 妯℃�佹鎺у埗 + profVisible: false // 楠岃瘉淇℃伅妯℃�佹 + } + + /** + * @description 鎼滅储鏉′欢鍒濆鍖� + */ + UNSAFE_componentWillMount () { + this.setState({ + actionlist: fromJS(this.props.config.action).toJS() + }) + } + + /** + * @description 鐩戝惉鍒版寜閽鍒舵椂锛岃Е鍙戞寜閽紪杈� + */ + UNSAFE_componentWillReceiveProps (nextProps) { + const { actionlist } = this.state + + if (!is(fromJS(nextProps.config.action), fromJS(this.props.config.action)) && !is(fromJS(nextProps.config.action), fromJS(actionlist))) { + this.setState({actionlist: fromJS(nextProps.config.action).toJS()}) + } + } + + /** + * @description 鎸夐挳椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞 + */ + handleList = (list, card) => { + const { config } = this.props + + if (card) { + this.setState({actionlist: list}) + this.handleAction(card) + } else { + this.setState({actionlist: list}, () => { + this.props.updateaction({...config, action: list}) + }) + } + } + + /** + * @description 鎸夐挳缂栬緫锛岃幏鍙栨寜閽〃鍗曚俊鎭� + */ + handleAction = (card) => { + const { menu } = this.props + let ableField = this.props.usefulFields.join(', ') + let functip = <div> + <p style={{marginBottom: '5px'}}>{this.state.dict['model.tooltip.func.innerface'].replace('@ableField', ableField)}</p> + <p>{this.state.dict['model.tooltip.func.outface']}</p> + </div> + + let menulist = [] + if (menu.fstMenuList) { + menulist = menu.fstMenuList.map(item => { + return { + value: item.MenuID, + label: item.text, + isLeaf: false + } + }) + } + + if (menu.fstMenuList && card.linkmenu && card.linkmenu.length > 0) { + let _param = { + func: 'sPC_Get_FunMenu', + ParentID: card.linkmenu[0], + systemType: options.sysType, + debug: 'Y' + } + + Api.getSystemConfig(_param).then(result => { + if (result.status) { + menulist = menulist.map(item => { + if (item.value === card.linkmenu[0]) { + item.children = result.data.map(item => { + let submenu = { + value: item.ParentID, + label: item.MenuNameP, + children: item.FunMenu.map(cell => { + return { + value: cell.MenuID, + label: cell.MenuName, + MenuID: cell.MenuID, + MenuName: cell.MenuName, + MenuNo: cell.MenuNo, + Ot: cell.Ot, + PageParam: cell.PageParam, + LinkUrl: cell.LinkUrl, + disabled: cell.MenuID === menu.MenuID + } + }) + } + + return submenu + }) + } + return item + }) + } else { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + } + + this.setState({ + visible: true, + card: card, + formlist: getActionForm(card, functip, this.props.config, this.props.usefulFields, this.props.type, menulist) + }) + }) + } else { + this.setState({ + visible: true, + card: card, + formlist: getActionForm(card, functip, this.props.config, this.props.usefulFields, this.props.type, menulist) + }) + } + } + + /** + * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎 + */ + editModalCancel = () => { + const { card } = this.state + + if (card.focus) { + let actionlist = fromJS(this.state.actionlist).toJS() + + actionlist = actionlist.filter(item => item.uuid !== card.uuid) + + this.setState({ + card: null, + actionlist: actionlist, + visible: false + }) + } else { + this.setState({ + card: null, + visible: false + }) + } + } + + /** + * @description 鎼滅储淇敼鍚庢彁浜や繚瀛� + * 1銆佸幓闄ょ郴缁熼粯璁ゆ悳绱㈡潯浠� + * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙 + * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚� + * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉 + */ + handleSubmit = () => { + const { config, menu } = this.props + const { card } = this.state + let _actionlist = fromJS(this.state.actionlist).toJS() + + this.actionFormRef.handleConfirm().then(btn => { + _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid) + + let labelrepet = false + _actionlist = _actionlist.map(item => { + if (item.uuid !== btn.uuid && item.label === btn.label) { + labelrepet = true + } + + if (item.uuid === btn.uuid) { + return btn + } else { + return item + } + }) + + if (labelrepet) { + notification.warning({ + top: 92, + message: this.state.dict['model.name.exist'] + ' !', + duration: 5 + }) + return + } + + this.setState({ + copying: true + }) + + let copyActionId = '' // 鎸夐挳涓哄鍒舵椂锛岃褰曞綋鍓嶆寜閽殑Id锛岃彍鍗曞彇娑堜繚瀛樻椂锛屽垹闄ゅ鍒舵寜閽厤缃俊鎭� + + /** + * @description 鎸夐挳淇濆瓨鏍¢獙 + * 1銆佹鏌ユ寜閽槸鍚︿负琛ㄥ崟鎴栬〃鍗曟爣绛鹃〉锛屽鍓嶅悗涓�鑷达紝鍒欏鍒跺叾鍐呭 + * 2銆佹鏌ユ寜閽槸鍚︿负鏍囩椤碉紝濡傚墠鍚庝竴鑷达紝鍒欏鍒舵爣绛鹃〉 + */ + new Promise(resolve => { + if ( + !card.originCard || + (btn.OpenType === 'pop' && card.originCard.OpenType !== 'pop') || + (['tab', 'blank'].includes(btn.OpenType) && !['tab', 'blank'].includes(card.originCard.OpenType)) || + (btn.OpenType === 'popview' && (!btn.createTab || card.originCard.OpenType !== 'popview' || !card.originCard.linkTab)) + ) { // 鎸夐挳涓嶆槸澶嶅埗锛屾垨鎸夐挳鍓嶅悗绫诲瀷涓嶄竴鑷存椂锛岀洿鎺ヤ繚瀛� + resolve('save') + } else if (btn.OpenType === 'pop' || btn.OpenType === 'tab' || btn.OpenType === 'blank') { + resolve('subconf') + } else if (btn.OpenType === 'popview') { + resolve('subtab') + } else { + resolve('save') + } + }).then(result => { // 鏌ヨ鍘熸寜閽厤缃俊鎭� + if (result === 'save' || result === 'subtab') return result + + return Api.getSystemConfig({ + func: 'sPC_Get_LongParam', + MenuID: card.originCard.uuid + }) + }).then(result => { // 澶嶅埗鎸夐挳閰嶇疆淇℃伅锛屼繚瀛樿嚦鏂版坊鍔犳寜閽� + if (result === 'save' || result === 'subtab') return result + + if (result.status && result.LongParam) { + let _LongParam = '' + + // 瑙f瀽閰嶇疆 + if (result.LongParam) { + try { + _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) + } catch (e) { + console.warn('Parse Failure') + _LongParam = '' + } + } + + let _temp = '' // 閰嶇疆淇℃伅绫诲瀷 + + // 淇敼妯℃�佹鏍囬鍚嶇О + if (btn.OpenType === 'pop' && _LongParam && _LongParam.type === 'Modal') { + try { + _LongParam.setting.title = btn.label + _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam))) + _temp = 'Modal' + } catch { + console.warn('Stringify Failure') + _LongParam = '' + _temp = '' + } + } else if (['tab', 'blank'].includes(btn.OpenType) && _LongParam && _LongParam.type === 'FormTab') { + try { + _LongParam.action = _LongParam.action.map(_btn => { + _btn.uuid = Utils.getuuid() + + return _btn + }) + _LongParam.tabgroups.forEach(_groupId => { + _LongParam[_groupId] = _LongParam[_groupId].map(_tab => { + _tab.uuid = Utils.getuuid() + + return _tab + }) + }) + _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam))) + _temp = 'FormTab' + } catch { + console.warn('Stringify Failure') + _LongParam = '' + _temp = '' + } + } + + if (!_temp) return 'save' + + let param = { + func: 'sPC_ButtonParam_AddUpt', + ParentID: menu.MenuID, + MenuID: btn.uuid, + MenuNo: menu.MenuNo, + Template: _temp, + MenuName: btn.label, + PageParam: JSON.stringify({Template: _temp}), + LongParam: _LongParam + } + + return Api.getSystemConfig(param) + } else { + if (!result.status) { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + } + return 'save' + } + }).then(result => { + if (result === 'save' || result === 'subtab') return result + + if (!result.status) { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + } else { + copyActionId = btn.uuid + } + + return 'save' + }).then(result => { // 鏌ヨ鍘熸寜閽叧鑱旀爣绛句俊鎭� + if (result === 'save') return result + + return Api.getSystemConfig({ + func: 'sPC_Get_LongParam', + MenuID: card.originCard.linkTab + }) + }).then(result => { // 鏍囩澶嶅埗 + if (result === 'save') return result + + let _LongParam = '' // 鏍囩閰嶇疆淇℃伅 + + if (!result.status) { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + } else if (result.LongParam) { + // 瑙f瀽鏍囩閰嶇疆 + try { + _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) + } catch (e) { + console.warn('Parse Failure') + _LongParam = '' + } + } + + if (!_LongParam) { + return 'save' + } else { + copyActionId = btn.linkTab + + return new Promise(resolve => { + this.copytab(btn, _LongParam, resolve) + }) + } + }).then(() => { + // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒� + let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0 + let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null + + if (_gridBtn) { + _gridBtn.display = _hasGridbtn + } else { + _gridBtn = { + display: _hasGridbtn, + Align: 'center', + IsSort: 'false', + uuid: Utils.getuuid(), + label: this.state.dict['model.form.column.action'], + type: 'action', + style: 'button', + show: 'horizontal', + Width: 120 + } + } + + this.setState({ + actionlist: _actionlist, + copying: false, + visible: false + }, () => { + this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}, copyActionId) + }) + }) + }) + } + + /** + * @description 鏍囩澶嶅埗 + * 1銆佷繚瀛樻寜閽叧鑱旂殑鏂版爣绛� + * 2銆佷繚瀛樻爣绛炬寜閽俊鎭� + * 3銆佷繚瀛樻柊鏍囩涓寜閽殑瀛愰厤缃俊鎭� + */ + copytab = (btn, _tab, _resolve) => { + let _LongParam = '' + + _tab.uuid = btn.linkTab + _tab.tabName = _tab.tabName + moment().format('YYYY-MM-DD HH:mm:ss') + _tab.tabNo = _tab.tabNo + moment().format('YYYY-MM-DD HH:mm:ss') + + let param = { + func: 'sPC_Tab_AddUpt', + MenuID: _tab.uuid, + MenuNo: _tab.tabNo, + Template: _tab.Template, + MenuName: _tab.tabName, + Remark: _tab.Remark, + PageParam: JSON.stringify({Template: _tab.Template}), + Sort: 0 + } + + let _oriActions = [] + + let btnParam = { + func: 'sPC_Button_AddUpt', + Type: 40, + ParentID: _tab.uuid, + MenuNo: _tab.tabNo, + Template: _tab.Template, + PageParam: '', + LongParam: '', + LText: '' + } + + try { + let _linkchange = {} + btnParam.LText = [] + + _tab.action = _tab.action.map((item, index) => { + let uuid = Utils.getuuid() + + if (item.OpenType === 'pop') { + _oriActions.push({ + prebtn: JSON.parse(JSON.stringify(item)), + curuuid: uuid, + Template: 'Modal' + }) + } else if (item.OpenType === 'popview') { + _linkchange[item.linkTab] = Utils.getuuid() + + item.linkTab = _linkchange[item.linkTab] + } + + item.uuid = uuid + + btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`) + + return item + }) + + if (_tab.funcs && _tab.funcs.length > 0) { + _tab.funcs = _tab.funcs.map(item => { + if (item.type === 'tab') { + item.linkTab = _linkchange[item.linkTab] + item.menuNo = '' + item.subfuncs = [] + } + + return item + }) + } + + btnParam.LText = btnParam.LText.join(' union all ') + btnParam.LText = Utils.formatOptions(btnParam.LText) + btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp) + + _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_tab))) + } catch { + console.warn('Stringify Failure') + _LongParam = '' + _resolve('save') + return + } + + param.LongParam = _LongParam + + new Promise(resolve => { + Api.getSystemConfig(param).then(response => { + if (response.status) { + resolve(true) + } else { + notification.warning({ + top: 92, + message: response.message, + duration: 5 + }) + resolve(false) + } + }) + }).then(result => { + if (!result) return result + if (!btnParam.LText) return true + + return Api.getSystemConfig(btnParam) + }).then(result => { + if (result === false || result === true) return result + + if (result.status) { + return true + } else { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + return false + } + }).then(result => { + if (!result) return result + if (_oriActions.length === 0) return true + + let deffers = _oriActions.map(item => { + return new Promise(resolve => { + Api.getSystemConfig({ + func: 'sPC_Get_LongParam', + MenuID: item.prebtn.uuid + }).then(response => { + if (!response.status || !response.LongParam) { + resolve(response) + } else { + let _param = { + func: 'sPC_ButtonParam_AddUpt', + ParentID: _tab.uuid, + MenuID: item.curuuid, + MenuNo: _tab.tabNo, + Template: item.Template, + MenuName: item.prebtn.label, + PageParam: JSON.stringify({Template: item.Template}), + LongParam: response.LongParam + } + Api.getSystemConfig(_param).then(resp => { + resolve(resp) + }) + } + }) + }) + }) + + return Promise.all(deffers) + }).then(result => { + let error = '' + + if (typeof(result) === 'object') { + result.forEach(resul => { + if (!resul.status && !error) { + error = resul + } + }) + } + + if (error) { + notification.warning({ + top: 92, + message: error.message, + duration: 5 + }) + } + + _resolve('save') + }) + } + + /** + * @description 鎸夐挳鍒犻櫎 + */ + deleteElement = (card) => { + const { config } = this.props + const { dict } = this.state + let _this = this + + confirm({ + content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋, + okText: dict['model.confirm'], + cancelText: this.state.dict['model.cancel'], + onOk() { + let _actionlist = fromJS(_this.state.actionlist).toJS() + + _actionlist = _actionlist.filter(item => item.uuid !== card.uuid) + + let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0 + let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null + + if (_gridBtn) { + _gridBtn.display = _hasGridbtn + } else { + _gridBtn = { + display: _hasGridbtn, + Align: 'center', + IsSort: 'false', + uuid: Utils.getuuid(), + label: this.state.dict['model.form.column.action'], + type: 'action', + style: 'button', + show: 'horizontal', + Width: 120 + } + } + + let delcard = { + type: 'action', + card: card + } + + _this.setState({ + actionlist: _actionlist + }, () => { + _this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}, '', delcard) + }) + }, + onCancel() {} + }) + } + + /** + * @description 楠岃瘉淇℃伅閰嶇疆 + */ + profileAction = (element) => { + this.setState({ + profVisible: true, + card: element + }) + } + + /** + * @description 楠岃瘉淇℃伅淇濆瓨 + */ + verifySubmit = () => { + const { config } = this.props + const { card } = this.state + + this.verifyRef.handleConfirm().then(res => { + let _actionlist = fromJS(this.state.actionlist).toJS() + _actionlist = _actionlist.filter(item => !item.origin || item.uuid === card.uuid) + + _actionlist = _actionlist.map(item => { + if (item.uuid === card.uuid) { + item.verify = res + } + + return item + }) + + this.setState({ + actionlist: _actionlist, + profVisible: false + }, () => { + this.props.updateaction({...config, action: _actionlist}) + }) + }) + } + + /** + * @description 鍒涘缓鎸夐挳瀛樺偍杩囩▼ + */ + creatFunc = () => { + const { config, menu } = this.props + let _config = fromJS(this.props.config).toJS() + + this.actionFormRef.handleConfirm().then(res => { + let btn = res // 鎸夐挳淇℃伅 + let newLText = '' // 鍒涘缓瀛樺偍杩囩▼sql + let DelText = '' // 鍒犻櫎瀛樺偍杩囩▼sql + + let _actionlist = fromJS(this.state.actionlist).toJS() + + _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid) + + let labelrepet = false + _actionlist = _actionlist.map(item => { + if (item.uuid !== btn.uuid && item.label === btn.label) { + labelrepet = true + } + + if (item.uuid === btn.uuid) { + return btn + } else { + return item + } + }) + + if (labelrepet) { + notification.warning({ + top: 92, + message: this.state.dict['model.name.exist'] + ' !', + duration: 5 + }) + return + } + + // 鍒涘缓瀛樺偍杩囩▼锛屽繀椤诲~鍐欏唴閮ㄥ嚱鏁板悕 + if (!btn.innerFunc) { + notification.warning({ + top: 92, + message: '璇峰~鍐欏唴閮ㄥ嚱鏁帮紒', + duration: 5 + }) + return + } + + new Promise(resolve => { + // 寮圭獥锛堣〃鍗曪級绫绘寜閽紝鍏堣幏鍙栨寜閽厤缃俊鎭紝濡傛灉灏氭湭閰嶇疆鎸夐挳鍒欎細鎶ラ敊骞剁粓姝€�� + // 鑾峰彇淇℃伅鍚庣敓鎴愬垹闄ゅ拰鍒涘缓瀛樺偍杩囩▼鐨勮鍙� + if (btn.OpenType === 'pop') { + Api.getSystemConfig({ + func: 'sPC_Get_LongParam', + MenuID: btn.uuid + }).then(res => { + let _LongParam = '' + if (res.status && res.LongParam) { + try { + _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam))) + } catch (e) { + console.warn('Parse Failure') + _LongParam = '' + } + } + + if (_LongParam) { + let fields = [] + if (_LongParam.groups.length > 0) { + _LongParam.groups.forEach(group => { + fields = [...fields, ...group.sublist] + }) + } else { + fields = _LongParam.fields + } + + let _param = { + funcName: btn.innerFunc, + name: _config.setting.tableName || '', + fields: fields, + menuNo: menu.MenuNo + } + newLText = Utils.formatOptions(DevUtils.getfunc(_param, btn, menu, _config)) + DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc)) + resolve(true) + } else { + notification.warning({ + top: 92, + message: '寮圭獥锛堣〃鍗曪級鎸夐挳锛岃鍏堥厤缃〃鍗曚俊鎭紒', + duration: 5 + }) + resolve(false) + } + }) + } else if (btn.OpenType === 'excelIn') { + if (btn.verify && btn.verify.sheet && btn.verify.columns && btn.verify.columns.length > 0) { + let _param = { + funcName: btn.innerFunc, + menuNo: menu.MenuNo + } + newLText = Utils.formatOptions(DevUtils.getexcelInfunc(_param, btn, menu)) + DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc)) + resolve(true) + } else { + notification.warning({ + top: 92, + message: '璇峰畬鍠勫鍏xcel楠岃瘉淇℃伅锛�', + duration: 5 + }) + resolve(false) + } + } else if (btn.OpenType === 'excelOut') { + let _param = { + innerFunc: btn.innerFunc + } + + newLText = Utils.formatOptions(DevUtils.getTableFunc(_param, menu, _config)) // 鍒涘缓瀛樺偍杩囩▼sql + DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc)) + + resolve(true) + } else { + let _param = { + funcName: btn.innerFunc, + name: _config.setting.tableName || '', + fields: '', + menuNo: menu.MenuNo + } + newLText = Utils.formatOptions(DevUtils.getfunc(_param, btn, menu, _config)) + DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc)) + resolve(true) + } + }).then(res => { + if (!res) return + + this.refs.btnCreatFunc.exec(btn.innerFunc, newLText, DelText).then(result => { + if (result !== 'success') return + + // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒� + let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0 + let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null + + if (_gridBtn) { + _gridBtn.display = _hasGridbtn + } else { + _gridBtn = { + display: _hasGridbtn, + Align: 'center', + IsSort: 'false', + uuid: Utils.getuuid(), + label: this.state.dict['model.form.column.action'], + type: 'action', + style: 'button', + show: 'horizontal', + Width: 120 + } + } + + this.setState({ + actionlist: _actionlist + }, () => { + this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}) + }) + }) + }) + }) + } + + /** + * @description 鎸夐挳鍙屽嚮瑙﹀彂瀛愰厤缃� + */ + btnDoubleClick = (element) => { + if (!element.origin && (element.OpenType === 'pop' || element.OpenType === 'popview' || element.OpenType === 'blank' || element.OpenType === 'tab')) { + this.props.setSubConfig(element) + } else { + notification.warning({ + top: 92, + message: '姝ゆ寜閽棤瀛愰厤缃」锛�', + duration: 5 + }) + } + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊 + */ + componentWillUnmount () { + this.setState = () => { + return + } + } + + render() { + const { config } = this.props + const { actionlist, visible, card, dict, copying, profVisible } = this.state + + return ( + <div className="model-custom-chart-action-list"> + <DragElement + list={actionlist} + setting={this.props.config.setting} + handleList={this.handleList} + handleMenu={this.handleAction} + deleteMenu={this.deleteElement} + profileMenu={this.profileAction} + doubleClickCard={this.btnDoubleClick} + /> + {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */} + <Modal + title={dict['model.action'] + '-' + (card && card.copyType === 'action' ? dict['model.copy'] : dict['model.edit'])} + visible={visible} + width={800} + maskClosable={false} + onCancel={this.editModalCancel} + footer={[ + card && !card.copyType ? <CreateFunc key="create" dict={dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null, + <Button key="cancel" onClick={this.editModalCancel}>{dict['model.cancel']}</Button>, + <Button key="confirm" type="primary" loading={copying} onClick={this.handleSubmit}>{dict['model.confirm']}</Button> + ]} + destroyOnClose + > + <ActionForm + dict={dict} + card={card} + tabs={this.props.tabs} + formlist={this.state.formlist} + inputSubmit={this.handleSubmit} + setting={config.setting} + wrappedComponentRef={(inst) => this.actionFormRef = inst} + /> + </Modal> + {/* 鎸夐挳浣跨敤绯荤粺瀛樺偍杩囩▼鏃讹紝楠岃瘉淇℃伅妯℃�佹 */} + <Modal + wrapClassName="model-table-action-verify-modal" + title={'楠岃瘉淇℃伅'} + visible={profVisible} + width={'75vw'} + maskClosable={false} + style={{minWidth: '900px', maxWidth: '1200px'}} + okText={dict['model.submit']} + onOk={this.verifySubmit} + onCancel={() => { this.setState({ profVisible: false }) }} + destroyOnClose + > + {card && !card.execMode && card.OpenType !== 'excelIn' && card.OpenType !== 'excelOut' ? + <VerifyCard + floor={this.props.type} + card={card} + dict={dict} + config={config} + columns={config.columns} + wrappedComponentRef={(inst) => this.verifyRef = inst} + /> : null + } + {card && card.execMode ? + <VerifyPrint + card={card} + dict={dict} + columns={config.columns} + wrappedComponentRef={(inst) => this.verifyRef = inst} + /> : null + } + {card && card.OpenType === 'excelIn' ? + <VerifyExcelIn + card={card} + dict={dict} + columns={config.columns} + wrappedComponentRef={(inst) => this.verifyRef = inst} + /> : null + } + {card && card.OpenType === 'excelOut' ? + <VerifyExcelOut + card={card} + dict={dict} + config={config} + wrappedComponentRef={(inst) => this.verifyRef = inst} + /> : null + } + </Modal> + </div> + ) + } +} + +export default ActionComponent \ No newline at end of file diff --git a/src/menu/actioncomponent/index.scss b/src/menu/actioncomponent/index.scss new file mode 100644 index 0000000..d2e31fb --- /dev/null +++ b/src/menu/actioncomponent/index.scss @@ -0,0 +1,93 @@ +.model-custom-chart-action-list { + position: absolute; + right: 0px; + z-index: 4; + + .anticon-question-circle { + color: #c49f47; + position: absolute; + left: 5px; + top: 5px; + } + + .ant-row .anticon-plus { + color: #26C281; + float: right; + padding: 5px; + margin-top: 20px; + } + + .page-card { + margin: 0px 0px 0px 0px; + padding: 15px 10px 0 0; + position: relative; + float: right; + + div { + cursor: move; + } + .edit { + position: absolute; + left: 0; + top: 0px; + color: #1890ff; + cursor: pointer; + display: none; + } + .edit.copy { + left: 20px; + color: #26C281; + } + .edit.close { + left: 40px; + color: #ff4d4f; + } + .edit.profile { + left: 60px; + color: purple; + } + button { + min-width: 65px; + cursor: move; + .anticon-table { + font-size: 10px; + position: absolute; + right: 1px; + bottom: 0px; + } + } + } + .page-card:hover { + .edit { + display: inline-block; + } + } +} + +.model-table-action-verify-modal { + .ant-modal { + top: 50px; + padding-bottom: 5px; + .ant-modal-body { + max-height: calc(100vh - 190px); + overflow-y: auto; + .ant-empty { + margin: 15vh 8px; + } + } + .ant-modal-body::-webkit-scrollbar { + width: 7px; + } + .ant-modal-body::-webkit-scrollbar-thumb { + border-radius: 5px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13); + background: rgba(0, 0, 0, 0.13); + } + .ant-modal-body::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); + border-radius: 3px; + border: 1px solid rgba(0, 0, 0, 0.07); + background: rgba(0, 0, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelin/columnform/index.jsx b/src/menu/actioncomponent/verifyexcelin/columnform/index.jsx new file mode 100644 index 0000000..2cf05f4 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/columnform/index.jsx @@ -0,0 +1,221 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Select, Button, Input, InputNumber, Radio } from 'antd' +import './index.scss' + +class ExcelInColumn extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + columns: PropTypes.array, // 鍒楀悕闆嗗悎 + columnChange: PropTypes.func // 淇敼鍑芥暟 + } + + state = { + editItem: null, // 缂栬緫鍏冪礌 + type: 'Nvarchar(50)', + locked: false + } + + edit = (record) => { + this.setState({ + editItem: record, + type: record.type || 'Nvarchar(50)' + }, () => { + if (!/^Nvarchar/.test(record.type)) { + this.props.form.setFieldsValue({ + min: record.min, + max: record.max + }) + } + }) + + this.props.form.setFieldsValue({ + Column: record.Column, + Text: record.Text, + required: record.required || 'true', + import: record.import || 'true', + type: record.type + }) + if (record.type === 'Int' || /^Decimal/ig.test(record.type)) { + this.setState({ + locked: true + }) + } else { + this.setState({ + locked: false + }) + } + } + + typeChange = (val) => { + this.setState({ + type: val + }, () => { + if (val === 'Int' || /^Decimal/ig.test(val)) { + this.props.form.setFieldsValue({ + required: 'true', + }) + this.setState({ + locked: true + }) + } else { + this.setState({ + locked: false + }) + } + }) + } + + + handleConfirm = () => { + // const { columns } = this.props + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.state.editItem ? this.state.editItem.uuid : '' + + if (/^Nvarchar/ig.test(values.type)) { + values.limit = values.type.match(/\d+/) ? values.type.match(/\d+/)[0] : '20000' + } else if (/^Decimal/ig.test(values.type)) { + values.limit = values.type.match(/\d+/ig)[1] + } else { + values.limit = '' + } + + this.props.columnChange(values) + this.setState({ + editItem: null, + locked: false, + type: 'Nvarchar(50)' + }) + this.props.form.setFieldsValue({ + Column: '', + Text: '', + required: 'true', + import: 'true', + type: 'Nvarchar(50)' + }) + } + }) + } + + render() { + const { dict } = this.props + const { getFieldDecorator } = this.props.form + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + let haslimit = !/^Nvarchar/.test(this.state.type) + + return ( + <Form {...formItemLayout} className="verify-form"> + <Row gutter={24}> + <Col span={7}> + <Form.Item label={dict['model.form.field']}> + {getFieldDecorator('Column', { + initialValue: '', + rules: [ + { + required: true, + message: dict['form.required.input'] + dict['model.form.field'] + '!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={dict['model.name']}> + {getFieldDecorator('Text', { + initialValue: '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + dict['model.name'] + '!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={dict['model.form.type']}> + {getFieldDecorator('type', { + initialValue: 'Nvarchar(50)' + })( + <Select onChange={this.typeChange}> + <Select.Option value="Nvarchar(10)"> Nvarchar(10) </Select.Option> + <Select.Option value="Nvarchar(20)"> Nvarchar(20) </Select.Option> + <Select.Option value="Nvarchar(50)"> Nvarchar(50) </Select.Option> + <Select.Option value="Nvarchar(100)"> Nvarchar(100) </Select.Option> + <Select.Option value="Nvarchar(256)"> Nvarchar(256) </Select.Option> + <Select.Option value="Nvarchar(512)"> Nvarchar(512) </Select.Option> + <Select.Option value="Nvarchar(1024)"> Nvarchar(1024) </Select.Option> + <Select.Option value="Nvarchar(2048)"> Nvarchar(2048) </Select.Option> + <Select.Option value="Nvarchar(max)"> Nvarchar(max) </Select.Option> + <Select.Option value="Int"> Int </Select.Option> + <Select.Option value="Decimal(18,0)"> Decimal(18,0) </Select.Option> + <Select.Option value="Decimal(18,2)"> Decimal(18,2) </Select.Option> + <Select.Option value="Decimal(18,4)"> Decimal(18,4) </Select.Option> + <Select.Option value="Decimal(18,6)"> Decimal(18,6) </Select.Option> + <Select.Option value="date"> date </Select.Option> + </Select> + )} + </Form.Item> + </Col> + <Col span={3} className="add"> + <Button onClick={this.handleConfirm} type="primary" className="mk-green"> + {dict['model.save']} + </Button> + </Col> + <Col span={7}> + <Form.Item label={dict['model.required']}> + {getFieldDecorator('required', { + initialValue: 'true' + })( + <Radio.Group disabled={this.state.locked}> + <Radio value="true">{dict['model.true']}</Radio> + <Radio value="false">{dict['model.false']}</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={dict['model.import']}> + {getFieldDecorator('import', { + initialValue: 'true' + })( + <Radio.Group> + <Radio value="true">{dict['model.true']}</Radio> + <Radio value="false">{dict['model.false']}</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + {haslimit ? <Col span={7}> + <Form.Item label={'鏈�灏忓��'}> + {getFieldDecorator('min', { + initialValue: '' + })(<InputNumber />)} + </Form.Item> + </Col> : null} + {haslimit ? <Col span={7}> + <Form.Item label={'鏈�澶у��'}> + {getFieldDecorator('max', { + initialValue: '' + })(<InputNumber />)} + </Form.Item> + </Col> : null} + </Row> + </Form> + ) + } +} + +export default Form.create()(ExcelInColumn) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelin/columnform/index.scss b/src/menu/actioncomponent/verifyexcelin/columnform/index.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/columnform/index.scss diff --git a/src/menu/actioncomponent/verifyexcelin/customscript/index.jsx b/src/menu/actioncomponent/verifyexcelin/customscript/index.jsx new file mode 100644 index 0000000..9b8ecee --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/customscript/index.jsx @@ -0,0 +1,325 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { Form, Row, Col, Button, notification, Modal, Icon, Tooltip, Radio, Select } from 'antd' +import moment from 'moment' + +import Utils from '@/utils/utils.js' +import Api from '@/api' +import CodeMirror from '@/templates/zshare/codemirror' +import './index.scss' + +class CustomForm extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + btn: PropTypes.object, // 鎸夐挳淇℃伅 + scripts: PropTypes.array, // 鑷畾涔夎剼鏈垪琛� + usefulfields: PropTypes.any, // 鍙敤瀛楁 + systemScripts: PropTypes.array, // 绯荤粺鑴氭湰 + scriptsChange: PropTypes.func // 琛ㄥ崟 + } + + state = { + editItem: null, + usefulfields: null, + loading: false, + verifySql: '' + } + + UNSAFE_componentWillMount () { + const {usefulfields, btn} = this.props + + let fields = usefulfields.map(item => item.Column) + if (!fields.includes('ID')) { + fields.unshift('ID') + } + if (!fields.includes('BID')) { + fields.unshift('BID') + } + + let _sql = `Declare @${btn.sheet} table (${usefulfields.map(item => item.Column + ' ' + item.type).join(',')},jskey nvarchar(50) ) + Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50), @retmsg nvarchar(4000),@tbid Nvarchar(512) + Select @ErrorCode='', @retmsg='' + ` + + this.setState({ + verifySql: _sql, + usefulfields: fields.join(', ') + }) + } + + UNSAFE_componentWillReceiveProps (nextProps) { + const { btn } = this.props + + if (nextProps.usefulfields && !is(fromJS(this.props.usefulfields), fromJS(nextProps.usefulfields))) { + + let fields = nextProps.usefulfields.map(item => item.Column) + if (!fields.includes('ID')) { + fields.unshift('ID') + } + if (!fields.includes('BID')) { + fields.unshift('BID') + } + + let _sql = `Declare @${btn.sheet} table (${nextProps.usefulfields.map(item => item.Column + ' ' + item.type).join(',')},jskey nvarchar(50) ) + Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50), @retmsg nvarchar(4000),@tbid Nvarchar(512) + Select @ErrorCode='', @retmsg='' + ` + + this.setState({ + verifySql: _sql, + usefulfields: fields.join(', ') + }) + } + } + + edit = (record) => { + this.setState({ + editItem: record + }) + + this.props.form.setFieldsValue({ + sql: record.sql, + position: record.position || 'back' + }) + } + + handleConfirm = () => { + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.state.editItem ? this.state.editItem.uuid : '' + + let _quot = values.sql.match(/'{1}/g) + let _lparen = values.sql.match(/\({1}/g) + let _rparen = values.sql.match(/\){1}/g) + + _quot = _quot ? _quot.length : 0 + _lparen = _lparen ? _lparen.length : 0 + _rparen = _rparen ? _rparen.length : 0 + + if (_quot % 2 !== 0) { + notification.warning({ + top: 92, + message: 'sql涓璡'蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + return + } else if (_lparen !== _rparen) { + notification.warning({ + top: 92, + message: 'sql涓�()蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + return + } else if (/--/ig.test(values.sql)) { + notification.warning({ + top: 92, + message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/', + duration: 5 + }) + return + } + + let error = Utils.verifySql(values.sql, 'customscript') + + if (error) { + notification.warning({ + top: 92, + message: 'sql涓笉鍙娇鐢�' + error, + duration: 5 + }) + return + } + + let tail = ` + aaa: + ` + + let _initsql = '' + this.props.scripts.forEach(script => { + if (this.state.editItem && this.state.editItem.uuid === script.uuid) return + if (script.status === 'false' || script.position !== 'init') return + + _initsql += ` + ${script.sql} + ` + }) + + let param = { + func: 's_debug_sql', + LText: this.state.verifySql + _initsql + values.sql + tail + } + + param.LText = param.LText.replace(/@\$|\$@/ig, '') + + 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) + + this.setState({loading: true}) + Api.getLocalConfig(param).then(res => { + if (res.status) { + this.setState({ + loading: false, + editItem: null + }, () => { + this.props.scriptsChange(values) + }) + this.props.form.setFieldsValue({ + sql: '' + }) + } else { + this.setState({loading: false}) + + Modal.error({ + title: res.message + }) + } + }) + } + }) + } + + handleCancel = () => { + this.setState({ + editItem: null + }) + + this.props.form.setFieldsValue({ + sql: '' + }) + } + + selectScript = (value, option) => { + const { usefulfields, btn } = this.props + + let _value = '' + if (value === 'default') { + let fields = usefulfields.map(col => col.Column).join(',') + + if (fields) { + fields = fields + ',' + } + + _value = `Insert into ${btn.sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid@,@username,@fullname,@BID@ From @${btn.sheet}` + } else { + _value = value + } + + let _sql = this.props.form.getFieldValue('sql') + if (_sql) { + _sql = _sql + ` + + ` + } + + _sql = _sql.replace(/\s{6}$/, '') + _sql = _sql + `/*${option.props.children}*/ + ` + _sql = _sql.replace(/\s{4}$/, '') + _sql = _sql + _value + + this.props.form.setFieldsValue({ + sql: _sql + }) + } + + render() { + const { systemScripts, btn } = this.props + const { usefulfields } = this.state + const { getFieldDecorator } = this.props.form + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <Form {...formItemLayout} className="verify-form" id="verify-excelin-custom-scripts"> + <Row gutter={24}> + {btn.sheet ? <Col span={8}> + <Form.Item label={'琛ㄥ悕'} style={{whiteSpace: 'nowrap', margin: 0}}> + {btn.sheet} + </Form.Item> + </Col> : null} + <Col span={16}> + <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0}}> + ErrorCode, retmsg + </Form.Item> + </Col> + {usefulfields ? <Col span={24} className="sqlfield"> + <Form.Item label={'鍙敤瀛楁'}> + {usefulfields}, jskey + </Form.Item> + </Col> : null} + <Col span={8} style={{whiteSpace: 'nowrap'}}> + <Form.Item style={{marginBottom: 0}} label={ + <Tooltip placement="bottomLeft" title={'鑷畾涔夎剼鏈笌榛樿sql浣嶇疆鍏崇郴銆�'}> + <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} /> + 鎵ц浣嶇疆 + </Tooltip> + }> + {getFieldDecorator('position', { + initialValue: 'front' + })( + <Radio.Group> + <Radio value="init">鍒濆鍖�</Radio> + <Radio value="front">sql鍓�</Radio> + <Radio value="back">sql鍚�</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={10}> + <Form.Item style={{marginBottom: 0}} label={'蹇嵎娣诲姞'}> + <Select + showSearch + filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} + onChange={this.selectScript} + getPopupContainer={() => document.getElementById('verify-excelin-custom-scripts')} + > + <Select.Option key="default" value={'default'}> + 榛樿sql + </Select.Option> + {systemScripts.map((option, i) => + <Select.Option key={i} value={option.value}> + {option.name} + </Select.Option> + )} + </Select> + </Form.Item> + </Col> + <Col span={6} className="add"> + <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 40}}> + 淇濆瓨 + </Button> + <Button onClick={this.handleCancel} style={{marginBottom: 15, marginLeft: 10}}> + 鍙栨秷 + </Button> + </Col> + <Col span={24} className="sql"> + <Form.Item label={'sql'}> + {getFieldDecorator('sql', { + initialValue: '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + 'sql!' + } + ] + })(<CodeMirror />)} + </Form.Item> + </Col> + </Row> + </Form> + ) + } +} + +export default Form.create()(CustomForm) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelin/customscript/index.scss b/src/menu/actioncomponent/verifyexcelin/customscript/index.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/customscript/index.scss diff --git a/src/menu/actioncomponent/verifyexcelin/index.jsx b/src/menu/actioncomponent/verifyexcelin/index.jsx new file mode 100644 index 0000000..b511cc1 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/index.jsx @@ -0,0 +1,947 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { fromJS } from 'immutable' +import { Form, Tabs, Row, Col, Input, Button, Table, Popconfirm, Icon, Tooltip, notification, Modal, message, InputNumber, Radio, Typography } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import Utils from '@/utils/utils.js' + +import UniqueForm from './uniqueform' +import ColumnForm from './columnform' +import CustomScript from './customscript' +import './index.scss' + +const { TabPane } = Tabs +const { confirm } = Modal +const { Paragraph } = Typography + +class VerifyCard extends Component { + static propTpyes = { + columns: PropTypes.array, // 鏄剧ず鍒� + dict: PropTypes.object, // 瀛楀吀椤� + card: PropTypes.object, + } + + state = { + verify: {}, + systemScripts: [], + activeKey: 'basemsg', + excelColumns: [ + { + title: this.props.dict['model.form.field'], + dataIndex: 'Column', + width: '16%', + editable: true + }, + { + title: this.props.dict['model.name'], + dataIndex: 'Text', + width: '15%', + editable: true + }, + { + title: this.props.dict['model.form.type'], + dataIndex: 'type', + width: '12%', + editable: true + }, + { + title: this.props.dict['model.required'], + dataIndex: 'required', + width: '10%', + editable: true, + render: (text, record) => record.required === 'true' ? this.props.dict['model.true'] : this.props.dict['model.false'] + }, + { + title: this.props.dict['model.import'], + dataIndex: 'import', + width: '10%', + editable: true, + render: (text, record) => record.import !== 'false' ? this.props.dict['model.true'] : this.props.dict['model.false'] + }, + { + title: '鏈�灏忓��', + dataIndex: 'min', + width: '10%', + editable: true + }, + { + title: '鏈�澶у��', + dataIndex: 'max', + width: '10%', + editable: true + }, + { + title: '鎿嶄綔', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + ( + <div> + <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span> + <Popconfirm + title={this.props.dict['header.form.query.delete']} + okText={this.props.dict['model.confirm']} + cancelText={this.props.dict['model.cancel']} + onConfirm={() => this.handleDelete(record, 'columns') + }> + <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span> + </Popconfirm> + </div> + ) + } + ], + uniqueColumns: [ + { + title: '瀛楁鍚�', + dataIndex: 'field', + width: '35%' + }, + { + title: '鎶ラ敊缂栫爜', + dataIndex: 'errorCode', + width: '12%' + }, + { + title: '楠岃瘉绫诲瀷', + dataIndex: 'verifyType', + width: '13%', + render: (text, record) => record.verifyType === 'logic' ? '閫昏緫楠岃瘉' : '鐗╃悊楠岃瘉' + }, + { + title: '鐘舵��', + dataIndex: 'status', + width: '15%', + 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: '25%', + dataIndex: 'operation', + render: (text, record) => + (<div> + <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', '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, 'unique')} 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['model.cancel']} + onConfirm={() => this.handleDelete(record, 'unique') + }> + <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span> + </Popconfirm> + </div>) + } + ], + scriptsColumns: [ + { + title: 'SQL', + dataIndex: 'sql', + width: '60%', + render: (text) => ( + <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph> + ) + }, + { + title: '鎵ц浣嶇疆', + dataIndex: 'position', + width: '10%', + render: (text, record) => { + let _text = '' + if (record.position === 'front') { + _text = 'sql鍓�' + } else if (record.position === 'init') { + _text = '鍒濆鍖�' + } else { + _text = 'sql鍚�' + } + return _text + } + }, + { + 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, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'scripts', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'scripts', '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, 'scripts')} 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['model.cancel']} + onConfirm={() => this.handleDelete(record, 'scripts') + }> + <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span> + </Popconfirm> + </div>) + } + ] + } + + UNSAFE_componentWillMount() { + const { columns, card } = this.props + let _verify = fromJS(card.verify || {range: 1}).toJS() + let _columns = _verify.columns || [] + + // 鍚屾鏄剧ず鍒� + if (_columns.length === 0) { + columns.forEach(col => { + if (!col.field) return + let _type = 'Nvarchar(50)' + let _limit = '50' + if (col.type === 'number' && !col.decimal) { + _type = 'Int' + _limit = '' + } else if (col.type === 'number') { + _type = 'Decimal(18,' + col.decimal + ')' + _limit = col.decimal + } + + let _cell = { + uuid: col.uuid, + Column: col.field, + Text: col.label, + type: _type, + limit: _limit, + import: 'true', + required: 'true' + } + + if (_type !== 'Nvarchar(50)') { + _cell.min = 0 + _cell.max = 999999 + } + + _columns.push(_cell) + }) + } else { + // 鏃ф暟鎹吋瀹� + _columns = _columns.map(col => { + col.required = col.required || 'true' + col.type = col.type || 'Nvarchar(50)' + + if (/^Nvarchar/ig.test(col.type)) { + col.limit = col.type.match(/\d+/)[0] + } else if (/^Decimal/ig.test(col.type)) { + col.limit = col.type.match(/\d+/ig)[1] + } else { + col.limit = '' + } + + return col + }) + } + + this.setState({ + verify: { + ..._verify, + default: _verify.default || 'true', + sheet: _verify.sheet || 'Sheet1', + range: _verify.range || 0, + columns: _columns, + scripts: _verify.scripts || [], + uniques: _verify.uniques || [] + } + }) + } + + componentDidMount () { + 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) + + _sParam.open_key = Utils.encrypt(_sParam.secretkey, _sParam.timestamp, true) // 浜戠鏁版嵁楠岃瘉 + + Api.getSystemConfig(_sParam).then(res => { + if (res.status) { + this.setState({ + systemScripts: res.data.map(item => { + return { + name: item.funcname, + value: Utils.formatOptions(item.longparam, true) + } + }) + }) + } else { + notification.warning({ + top: 92, + message: res.message, + duration: 5 + }) + } + }) + } + + columnFieldInput = () => { + const { columns } = this.props + const { verify } = this.state + + let _columns = JSON.parse(JSON.stringify(verify.columns)) + + let _cols = _columns.map(col => col.Column ) + + columns.forEach(col => { + if (col.field && !_cols.includes(col.field)) { + let _type = 'Nvarchar(50)' + let _limit = '50' + if (col.type === 'number' && !col.decimal) { + _type = 'Int' + _limit = '' + } else if (col.type === 'number') { + _type = 'Decimal(18,' + col.decimal + ')' + _limit = col.decimal + } + + let _cell = { + uuid: col.uuid, + Column: col.field, + Text: col.label, + type: _type, + limit: _limit, + import: 'true', + required: 'true' + } + + if (_type !== 'Nvarchar(50)') { + _cell.min = 0 + _cell.max = 999999 + } + + _columns.push(_cell) + } + }) + + this.setState({ + verify: { + ...verify, + columns: _columns + } + }) + } + + clearField = () => { + const { verify } = this.state + const _this = this + + confirm({ + content: `纭畾娓呯┖Excel鍒楀悧锛焋, + okText: this.props.dict['model.confirm'], + cancelText: this.props.dict['model.cancel'], + onOk() { + _this.setState({ + verify: { + ...verify, + columns: [] + } + }) + }, + onCancel() {} + }) + } + + columnChange = (values) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + + if (values.uuid) { + verify.columns = verify.columns.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + values.uuid = Utils.getuuid() + verify.columns.push(values) + } + + this.setState({ + verify: verify + }) + } + + uniqueChange = (values) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + + if (values.uuid) { + verify.uniques = verify.uniques.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + values.uuid = Utils.getuuid() + verify.uniques.push(values) + } + + this.setState({ + verify: verify + }) + } + + scriptsChange = (values) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + + if (values.uuid) { + verify.scripts = verify.scripts.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + values.uuid = Utils.getuuid() + verify.scripts.push(values) + } + + this.setState({ + verify: verify + }) + } + + handleDelete = (record, type) => { + const { verify } = this.state + + if (type === 'columns') { + verify.columns = verify.columns.filter(item => item.uuid !== record.uuid) + } else if (type === 'scripts') { + verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid) + } else if (type === 'unique') { + verify.uniques = verify.uniques.filter(item => item.uuid !== record.uuid) + } + + this.setState({ verify: verify }) + } + + handleEdit = (record, type) => { + if (type === 'columns') { + this.columnForm.edit(record) + } else if (type === 'scripts') { + this.scriptsForm.edit(record) + } else if (type === 'unique') { + this.uniqueForm.edit(record) + } + + let node = document.getElementById('verify-excel-box-tab').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) + } + } + + handleStatus = (record, type) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + record.status = record.status === 'false' ? 'true' : 'false' + + if (type === 'scripts') { + verify.scripts = verify.scripts.map(item => { + if (item.uuid === record.uuid) { + return record + } else { + return item + } + }) + } else if (type === 'unique') { + verify.uniques = verify.uniques.map(item => { + if (item.uuid === record.uuid) { + return record + } else { + return item + } + }) + } + + this.setState({ + verify: verify + }) + } + + handleUpDown = (record, type, direction) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + let index = 0 + + if (type === 'columns') { + verify.columns = verify.columns.filter((item, i) => { + if (item.uuid === record.uuid) { + index = i + } + + return item.uuid !== record.uuid + }) + if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) { + return + } + + if (direction === 'up') { + verify.columns.splice(index - 1, 0, record) + } else { + verify.columns.splice(index + 1, 0, record) + } + } else if (type === 'unique') { + verify.uniques = verify.uniques.filter((item, i) => { + if (item.uuid === record.uuid) { + index = i + } + + return item.uuid !== record.uuid + }) + if ((index === 0 && direction === 'up') || (index === verify.uniques.length && direction === 'down')) { + return + } + + if (direction === 'up') { + verify.uniques.splice(index - 1, 0, record) + } else { + verify.uniques.splice(index + 1, 0, record) + } + } else if (type === 'scripts') { + verify.scripts = verify.scripts.filter((item, i) => { + if (item.uuid === record.uuid) { + index = i + } + + return item.uuid !== record.uuid + }) + if ((index === 0 && direction === 'up') || (index === verify.scripts.length && direction === 'down')) { + return + } + + if (direction === 'up') { + verify.scripts.splice(index - 1, 0, record) + } else { + verify.scripts.splice(index + 1, 0, record) + } + } + + this.setState({ + verify: verify + }) + } + + handleConfirm = () => { + const { verify } = this.state + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let _verify = {...verify, ...values} + + let cols = _verify.columns.map(col => col.Column) + cols = Array.from(new Set(cols)) + + if (_verify.columns.length === 0) { + notification.warning({ + top: 92, + message: '璇疯缃瓻xcel鍒楀瓧娈�!', + duration: 5 + }) + return + } else if (_verify.columns.length > cols.length) { + notification.warning({ + top: 92, + message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!', + duration: 5 + }) + return + } else if (_verify.range === 1) { + let tEmptys = _verify.columns.filter(op => !op.Text) + if (tEmptys.length > 0) { + notification.warning({ + top: 92, + message: '蹇界暐棣栬鏃讹紝浼氫娇鐢═ext鍊兼牎楠孍xcel棣栬鍐呭锛孴ext鍊间笌Excel琛ㄩ琛屽唴瀹圭浉鍚岋紝涓斿潎涓嶅彲涓虹┖锛�', + duration: 5 + }) + return + } + } + + let _loading = false + if (this.columnForm && this.columnForm.state.editItem) { + _loading = true + this.setState({activeKey: 'excelcolumn'}) + } else if (this.scriptsForm && this.scriptsForm.state.editItem) { + _loading = true + this.setState({activeKey: 'scripts'}) + } else if (this.uniqueForm && this.uniqueForm.state.editItem) { + _loading = true + this.setState({activeKey: 'unique'}) + } + + if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) { + _loading = true + this.setState({activeKey: 'scripts'}) + } + + if (_loading) { + confirm({ + content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氭彁浜ゅ悧锛焋, + okText: this.props.dict['model.confirm'], + cancelText: this.props.dict['model.cancel'], + onOk() { + resolve(_verify) + }, + onCancel() {} + }) + } else { + resolve(_verify) + } + } else { + notification.warning({ + top: 92, + message: '璇疯缃瓻xcel琛ㄥ悕!', + duration: 5 + }) + } + }) + }) + } + + onOptionChange = (e, key) => { + const { verify } = this.state + let value = e.target.value + + this.setState({ + verify: {...verify, default: value} + }) + } + + showError = (errorType) => { + if (errorType === 'S') { + notification.success({ + top: 92, + message: '鎵ц鎴愬姛锛�', + duration: 2 + }) + } else if (errorType === 'Y') { + Modal.success({ + title: '鎵ц鎴愬姛锛�' + }) + } else if (errorType === 'F') { + notification.error({ + className: 'notification-custom-error', + top: 92, + message: '鎵ц澶辫触锛�', + duration: 10 + }) + } else if (errorType === 'N') { + notification.error({ + top: 92, + message: '鎵ц澶辫触锛�', + duration: 10 + }) + } else if (errorType === 'E') { + Modal.error({ + title: '鎵ц澶辫触锛�' + }) + } else if (errorType === 'NM') { + message.error('鎵ц澶辫触锛�') + } + } + + timeChange = (val, type) => { + const { verify } = this.state + + this.setState({ + verify: {...verify, [type]: val} + }) + } + + tabchange = (val) => { + const { activeKey } = this.state + + if (activeKey === 'basemsg') { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + this.setState({activeKey: val}) + } + }) + } else { + this.setState({activeKey: val}) + } + } + + render() { + const { card } = this.props + const { getFieldDecorator } = this.props.form + const { verify, excelColumns, scriptsColumns, uniqueColumns, activeKey } = this.state + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <div id="verify-excel-box-tab"> + <Tabs activeKey={activeKey} className="verify-card-box" onChange={this.tabchange}> + <TabPane tab="鍩虹楠岃瘉" key="basemsg"> + <Form {...formItemLayout}> + <Row gutter={24}> + <Col span={8}> + <Form.Item label={this.props.dict['model.form.tablename']}> + {getFieldDecorator('sheet', { + initialValue: verify.sheet || '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + this.props.dict['model.form.tablename'] + '!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={ + <Tooltip placement="bottomLeft" title="蹇界暐棣栬鏃讹紝浼氭牎楠宔xcel涓〃澶村悕绉颁笌excel鍒楄缃槸鍚︿竴鑷淬��"> + <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}}/> + 蹇界暐琛� + </Tooltip> + }> + {getFieldDecorator('range', { + initialValue: verify.range || 0 + })(<InputNumber min={0} max={100} precision={0} />)} + </Form.Item> + </Col> + {card.intertype === 'inner' && !card.innerFunc ? <Col span={8}> + <Form.Item label={'榛樿sql'}> + <Radio.Group value={verify.default} onChange={this.onOptionChange}> + <Radio value="true">鎵ц</Radio> + <Radio value="false">涓嶆墽琛�</Radio> + </Radio.Group> + </Form.Item> + </Col> : null} + </Row> + </Form> + </TabPane> + <TabPane tab={ + <span> + Excel鍒楄缃� + {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null} + </span> + } key="excelcolumn"> + <ColumnForm + dict={this.props.dict} + columns={verify.columns} + columnChange={this.columnChange} + wrappedComponentRef={(inst) => this.columnForm = inst} + /> + <Button className="excel-col-add mk-green" title="娣诲姞鏄剧ず鍒楀瓧娈�" onClick={this.columnFieldInput}> + 鍚屾鏄剧ず鍒� + </Button> + <Button className="excel-col-add mk-red" title="娓呯┖Excel鍒�" onClick={this.clearField}> + 娓呯┖Excel鍒� + </Button> + <Table + bordered + rowKey="uuid" + className="custom-table excel-custom-table" + dataSource={verify.columns} + columns={excelColumns} + pagination={false} + /> + </TabPane> + {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={ + <span> + 鍞竴鎬ч獙璇� + {verify.uniques.length ? <span className="count-tip">{verify.uniques.length}</span> : null} + </span> + } key="unique"> + <UniqueForm + fields={verify.columns} + dict={this.props.dict} + uniqueChange={this.uniqueChange} + wrappedComponentRef={(inst) => this.uniqueForm = inst} + /> + <Table + bordered + rowKey="uuid" + className="custom-table" + dataSource={verify.uniques} + columns={uniqueColumns} + pagination={false} + /> + </TabPane> : null} + {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={ + <span> + 鑷畾涔夎剼鏈� + {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null} + </span> + } key="scripts"> + <CustomScript + dict={this.props.dict} + btn={this.props.card} + usefulfields={verify.columns} + scripts={verify.scripts} + systemScripts={this.state.systemScripts} + scriptsChange={this.scriptsChange} + wrappedComponentRef={(inst) => this.scriptsForm = inst} + /> + <Table + bordered + rowKey="uuid" + className="custom-table" + dataSource={verify.scripts} + columns={scriptsColumns} + pagination={false} + /> + </TabPane> : null} + <TabPane tab="淇℃伅鎻愮ず" key="tip"> + <Form {...formItemLayout}> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> S </span> + <Button onClick={() => {this.showError('S')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> Y </span> + <Button onClick={() => {this.showError('Y')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> N </span> + <Button onClick={() => {this.showError('N')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> F </span> + <Button onClick={() => {this.showError('F')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> E </span> + <Button onClick={() => {this.showError('E')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> NM </span> + <Button onClick={() => {this.showError('NM')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> -1 </span> + 涓嶆彁绀� + </Form.Item> + </Col> + </Row> + </Form> + </TabPane> + </Tabs> + </div> + ) + } +} + +export default Form.create()(VerifyCard) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelin/index.scss b/src/menu/actioncomponent/verifyexcelin/index.scss new file mode 100644 index 0000000..00808ca --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/index.scss @@ -0,0 +1,86 @@ +.verify-card-box { + .ant-tabs-nav-scroll { + text-align: center; + } + .ant-tabs-content { + min-height: 40vh; + } + table tr td { + word-wrap: break-word; + word-break: break-word; + } + .ant-input-number { + width: 100%; + } + .count-tip { + position: absolute; + top: 0px; + color: #1890ff; + font-size: 12px; + } + .verify-form { + .sql { + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + padding-top: 4px; + } + .CodeMirror { + height: 350px; + } + } + .sqlfield { + .ant-form-item { + margin-bottom: 5px; + } + .ant-form-item-control { + line-height: 24px; + } + .ant-form-item-label { + line-height: 25px; + } + .ant-form-item-children { + line-height: 22px; + } + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + } + } + .add { + padding-top: 4px; + } + } + .custom-table .ant-empty { + margin: 20px 8px!important; + } + .excel-custom-table { + position: relative; + top: -25px; + } + .errorval { + display: inline-block; + width: 30px; + } + .operation-btn { + display: inline-block; + font-size: 16px; + padding: 0 5px; + cursor: pointer; + } + .ant-tabs-tabpane { + position: relative; + .excel-col-add { + position: relative; + float: right; + right: -9px; + margin-right: 10px; + top: -40px; + z-index: 1; + } + } +} \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx new file mode 100644 index 0000000..221bf91 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx @@ -0,0 +1,150 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Select, Button } from 'antd' +import './index.scss' + + +class UniqueForm extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + fields: PropTypes.array, // 琛ㄥ崟瀛楁 + uniqueChange: PropTypes.func // 淇敼鍑芥暟 + } + + state = { + editItem: null // 缂栬緫鍏冪礌 + } + + edit = (record) => { + this.setState({ + editItem: record + }) + + this.props.form.setFieldsValue({ + field: record.field.split(','), + errorCode: record.errorCode, + verifyType: record.verifyType || 'physical' + }) + } + + + handleConfirm = () => { + const { fields } = this.props + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.state.editItem ? this.state.editItem.uuid : '' + values.fieldlabel = values.field.map(field => { + let item = fields.filter(cell => cell.Column === field)[0] + let label = '' + if (item) { + label = item.Text + } + return label + }) + + values.fieldlabel = values.fieldlabel.join(',') + values.field = values.field.join(',') + + this.setState({ + editItem: null + }, () => { + this.props.uniqueChange(values) + }) + this.props.form.setFieldsValue({ + field: [], + }) + } + }) + } + + render() { + const { getFieldDecorator } = this.props.form + const { fields } = this.props + + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <Form {...formItemLayout} className="verify-form" id="verifycard1"> + <Row gutter={24}> + <Col span={8}> + <Form.Item label={'鍒楀悕'}> + {getFieldDecorator('field', { + initialValue: [], + rules: [ + { + required: true, + message: this.props.dict['form.required.select'] + '鍒楀悕!' + } + ] + })( + <Select + mode="multiple" + > + <Select.Option key="bid" value="BID">BID</Select.Option> + {fields.map(item => ( + <Select.Option key={item.uuid} value={item.Column}>{item.Text}</Select.Option> + ))} + </Select> + )} + </Form.Item> + </Col> + <Col span={6}> + <Form.Item label={'鎶ラ敊缂栫爜'}> + {getFieldDecorator('errorCode', { + initialValue: 'E', + rules: [ + { + required: true, + message: this.props.dict['form.required.select'] + '鎶ラ敊缂栫爜!' + } + ] + })( + <Select> + <Select.Option value="E"> E </Select.Option> + <Select.Option value="N"> N </Select.Option> + <Select.Option value="F"> F </Select.Option> + <Select.Option value="NM"> NM </Select.Option> + </Select> + )} + </Form.Item> + </Col> + <Col span={6}> + <Form.Item label={'楠岃瘉绫诲瀷'}> + {getFieldDecorator('verifyType', { + initialValue: 'physical', + rules: [ + { + required: true, + message: this.props.dict['form.required.select'] + '楠岃瘉绫诲瀷!' + } + ] + })( + <Select> + <Select.Option value="physical"> 鐗╃悊楠岃瘉 </Select.Option> + <Select.Option value="logic"> 閫昏緫楠岃瘉 </Select.Option> + </Select> + )} + </Form.Item> + </Col> + <Col span={4} className="add"> + <Button onClick={this.handleConfirm} className="mk-green"> + 淇濆瓨 + </Button> + </Col> + </Row> + </Form> + ) + } +} + +export default Form.create()(UniqueForm) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss diff --git a/src/menu/actioncomponent/verifyexcelout/columnform/index.jsx b/src/menu/actioncomponent/verifyexcelout/columnform/index.jsx new file mode 100644 index 0000000..56f31eb --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelout/columnform/index.jsx @@ -0,0 +1,116 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Button, Input, InputNumber } from 'antd' +import './index.scss' + +class ExcelOutColumn extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + columns: PropTypes.array, // 鍒楀悕闆嗗悎 + columnChange: PropTypes.func // 淇敼鍑芥暟 + } + + state = { + editItem: null // 缂栬緫鍏冪礌 + } + + edit = (record) => { + this.setState({ + editItem: record + }) + + this.props.form.setFieldsValue({ + Column: record.Column, + Text: record.Text, + Width: record.Width + }) + } + + + handleConfirm = () => { + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.state.editItem ? this.state.editItem.uuid : '' + + this.props.columnChange(values) + this.setState({ + editItem: null + }) + this.props.form.setFieldsValue({ + Column: '', + Text: '', + Width: 20 + }) + } + }) + } + + render() { + const { dict } = this.props + const { getFieldDecorator } = this.props.form + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <Form {...formItemLayout} className="verify-form"> + <Row gutter={24}> + <Col span={7}> + <Form.Item label={dict['model.form.field']}> + {getFieldDecorator('Column', { + initialValue: '', + rules: [ + { + required: true, + message: dict['form.required.input'] + dict['model.form.field'] + '!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={dict['model.name']}> + {getFieldDecorator('Text', { + initialValue: '', + rules: [ + { + required: true, + message: dict['form.required.input'] + dict['model.name'] + '!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={dict['model.form.columnWidth']}> + {getFieldDecorator('Width', { + initialValue: 20, + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + dict['model.form.columnWidth'] + '!' + } + ] + })(<InputNumber min={5} max={200} precision={0} />)} + </Form.Item> + </Col> + <Col span={3} className="add"> + <Button onClick={this.handleConfirm} type="primary" className="mk-green"> + 淇濆瓨 + </Button> + </Col> + </Row> + </Form> + ) + } +} + +export default Form.create()(ExcelOutColumn) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelout/columnform/index.scss b/src/menu/actioncomponent/verifyexcelout/columnform/index.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelout/columnform/index.scss diff --git a/src/menu/actioncomponent/verifyexcelout/index.jsx b/src/menu/actioncomponent/verifyexcelout/index.jsx new file mode 100644 index 0000000..a2fd460 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelout/index.jsx @@ -0,0 +1,602 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { fromJS } from 'immutable' +import { Form, Tabs, Row, Col, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber, Radio } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import Utils from '@/utils/utils.js' + +import ColumnForm from './columnform' +import CodeMirror from '@/templates/zshare/codemirror' +import './index.scss' + +const { TabPane } = Tabs +const { confirm } = Modal + +class VerifyCard extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + config: PropTypes.object, + card: PropTypes.object, + } + + state = { + verify: {}, + defaultscript: '', // 鑷畾涔夎剼鏈� + excelColumns: [ + { + title: this.props.dict['model.form.field'], + dataIndex: 'Column', + width: '25%' + }, + { + title: this.props.dict['model.name'], + dataIndex: 'Text', + width: '25%' + }, + { + title: this.props.dict['model.form.columnWidth'], + dataIndex: 'Width', + width: '25%' + }, + { + title: '鎿嶄綔', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + ( + <div> + <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span> + <Popconfirm + title={this.props.dict['header.form.query.delete']} + okText={this.props.dict['model.confirm']} + cancelText={this.props.dict['model.cancel']} + onConfirm={() => this.handleDelete(record, 'columns') + }> + <span style={{color: '#ff4d4f', cursor: 'pointer'}}><Icon type="delete" /></span> + </Popconfirm> + </div> + ) + } + ] + } + + UNSAFE_componentWillMount() { + const { config, card } = this.props + let _verify = {} + + if (card.verify) { + _verify = fromJS(card.verify).toJS() + } + + _verify.enable = _verify.enable || 'false' + + // 鍚屾鏄剧ず鍒� + if (!_verify.columns || _verify.columns.length === 0) { + _verify.columns = [] + config.columns.forEach(item => { + if (!item.field) return + + _verify.columns.push({ + Column: item.field, + Text: item.label, + Width: 20, + uuid: Utils.getuuid() + }) + }) + } + + if (card.intertype !== 'inner' || card.innerFunc) { + _verify.enable = 'false' + } + + let defaultscript = '' + if (!_verify.script && card.intertype === 'inner' && !card.innerFunc) { + let search = this.formatSearch(config.search) + search = Utils.joinMainSearchkey(search) + search = search ? 'where ' + search : '' + + defaultscript = `update ${config.setting.tableName || ''} set idefine5= idefine5+1 ,modifydate=getdate(),cdefine5='宸插鍑�',modifyuserid=@userid@ ${search}` + } + + + this.setState({ + verify: _verify, + defaultscript: defaultscript + }) + } + + /** + * @description 鑾峰彇鍏ㄩ儴鎼滅储鏉′欢 + * @param {Array} searches 鎼滅储鏉′欢鏁扮粍 + */ + formatSearch (searches) { + if (!searches || searches.length === 0) return [] + + let newsearches = [] + searches.forEach(search => { + let item = { + key: search.field, + match: search.match, + type: search.type, + label: search.label, + value: `@${search.field}@`, + required: search.required === 'true' + } + if (item.type === 'group') { + let copy = fromJS(item).toJS() + copy.key = search.datefield + + item.value = `@${search.field}@` + item.match = '=' + + copy.type = 'daterange' + copy.match = 'between' + copy.value = [`@${search.datefield}@`, `@${search.datefield}1@`] + + if (search.transfer === 'true') { + newsearches.push(item) + } + newsearches.push(copy) + return + } else if (item.type === 'dateweek') { + item.value = [`@${search.field}@`, `@${search.field}1@`] + } else if (item.type === 'daterange') { + item.value = [`@${search.field}@`, `@${search.field}1@`] + } else if (item.type === 'multiselect') { + item.value = [`@${search.field}@`] + } + newsearches.push(item) + }) + + return newsearches + } + + columnChange = (values) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + + if (values.uuid) { + verify.columns = verify.columns.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + let fields = verify.columns.map(item => item.Column) + if (fields.includes(values.Column)) { + notification.warning({ + top: 92, + message: values.Column + '瀛楁宸插瓨鍦紒', + duration: 5 + }) + return + } + values.uuid = Utils.getuuid() + verify.columns.push(values) + } + + this.setState({ + verify: verify + }) + } + + handleDelete = (record, type) => { + const { verify } = this.state + + verify.columns = verify.columns.filter(item => item.uuid !== record.uuid) + + this.setState({ verify: verify }) + } + + handleEdit = (record, type) => { + this.columnForm.edit(record) + + let node = document.getElementById('verify-excelout-box-tab').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, type, direction) => { + let verify = JSON.parse(JSON.stringify(this.state.verify)) + let index = 0 + + verify.columns = verify.columns.filter((item, i) => { + if (item.uuid === record.uuid) { + index = i + } + + return item.uuid !== record.uuid + }) + if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) { + return + } + + if (direction === 'up') { + verify.columns.splice(index - 1, 0, record) + } else { + verify.columns.splice(index + 1, 0, record) + } + + this.setState({ + verify: verify + }) + } + + showError = (errorType) => { + if (errorType === 'S') { + notification.success({ + top: 92, + message: '鎵ц鎴愬姛锛�', + duration: 2 + }) + } else if (errorType === 'Y') { + Modal.success({ + title: '鎵ц鎴愬姛锛�' + }) + } else if (errorType === 'F') { + notification.error({ + className: 'notification-custom-error', + top: 92, + message: '鎵ц澶辫触锛�', + duration: 10 + }) + } else if (errorType === 'N') { + notification.error({ + top: 92, + message: '鎵ц澶辫触锛�', + duration: 10 + }) + } else if (errorType === 'E') { + Modal.error({ + title: '鎵ц澶辫触锛�' + }) + } else if (errorType === 'NM') { + message.error('鎵ц澶辫触锛�') + } + } + + timeChange = (val, type) => { + const { verify } = this.state + + this.setState({ + verify: {...verify, [type]: val} + }) + } + + handleConfirm = () => { + let verify = fromJS(this.state.verify).toJS() + + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + let _cols = verify.columns.map(col => col.Column) + let _vcols = Array.from(new Set(_cols)) + + if (_cols.length > _vcols.length) { + notification.warning({ + top: 92, + message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!', + duration: 5 + }) + + return + } + + if (verify.enable === 'true') { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.sql = values.sql || '' + + let _quot = values.sql.match(/'{1}/g) + let _lparen = values.sql.match(/\({1}/g) + let _rparen = values.sql.match(/\){1}/g) + + _quot = _quot ? _quot.length : 0 + _lparen = _lparen ? _lparen.length : 0 + _rparen = _rparen ? _rparen.length : 0 + + if (_quot % 2 !== 0) { + notification.warning({ + top: 92, + message: 'sql涓璡'蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + return + } else if (_lparen !== _rparen) { + notification.warning({ + top: 92, + message: 'sql涓�()蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + return + } else if (/--/ig.test(values.sql)) { + notification.warning({ + top: 92, + message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/', + duration: 5 + }) + return + } + + let error = Utils.verifySql(values.sql, 'customscript') + + if (error) { + notification.warning({ + top: 92, + message: 'sql涓笉鍙娇鐢�' + error, + duration: 5 + }) + return + } + + let param = { + func: 's_debug_sql', + LText: values.sql + } + + param.LText = param.LText.replace(/@\$|\$@/ig, '') + + 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(res => { + if (res.status) { + resolve({...verify, script: values.sql}) + } else { + Modal.error({ + title: res.message + }) + } + }) + } else { + notification.warning({ + top: 92, + message: '鑷畾涔夎剼鏈笉鍙负绌猴紒', + duration: 5 + }) + } + }) + } else { + resolve(verify) + } + }) + } + + changeEnable = (e) => { + const { verify } = this.state + + this.setState({ + verify: {...verify, enable: e.target.value} + }) + } + + columnFieldInput = () => { + const { config } = this.props + const { verify } = this.state + + let columns = fromJS(verify.columns).toJS() + let fields = columns.map(item => item.Column) + + config.columns.forEach(item => { + if (fields.includes(item.field) || !item.field) return + fields.push(item.field) + + columns.push({ + Column: item.field, + Text: item.label, + Width: 20, + uuid: Utils.getuuid() + }) + }) + + this.setState({ + verify: {...verify, columns: columns} + }) + } + + clearField = () => { + const { verify } = this.state + const _this = this + + confirm({ + content: `纭畾娓呯┖Excel鍒楀悧锛焋, + okText: this.props.dict['model.confirm'], + cancelText: this.props.dict['model.cancel'], + onOk() { + _this.setState({ + verify: { + ...verify, + columns: [] + } + }) + }, + onCancel() {} + }) + } + + render() { + const { card } = this.props + const { verify, excelColumns, defaultscript } = this.state + const { getFieldDecorator } = this.props.form + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <div id="verify-excelout-box-tab"> + <Tabs defaultActiveKey="1" className="verify-card-box" onChange={this.tabchange}> + <TabPane tab={ + <span> + Excel瀵煎嚭鍒� + {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null} + </span> + } key="1"> + <ColumnForm + dict={this.props.dict} + columnChange={this.columnChange} + wrappedComponentRef={(inst) => this.columnForm = inst} + /> + <Button className="excel-col-add mk-green" title="娣诲姞鏄剧ず鍒楀瓧娈�" onClick={this.columnFieldInput}> + 鍚屾鏄剧ず鍒� + </Button> + <Button className="excel-col-add mk-red" title="娓呯┖Excel鍒�" onClick={this.clearField}> + 娓呯┖Excel鍒� + </Button> + <Table + bordered + rowKey="uuid" + className="custom-table" + dataSource={verify.columns} + columns={excelColumns} + pagination={false} + /> + </TabPane> + {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={ + <span> + 鑷畾涔夎剼鏈� + {verify.enable === 'true' ? <span className="count-tip">1</span> : null} + </span> + } key="6"> + <Form {...formItemLayout} className="verify-form"> + <Row gutter={24}> + <Col span={8}> + <Form.Item style={{marginBottom: 10}} label={'鍚敤'}> + <Radio.Group defaultValue={verify.enable || 'false'} onChange={this.changeEnable}> + <Radio value="true">鏄�</Radio> + <Radio value="false">鍚�</Radio> + </Radio.Group> + </Form.Item> + </Col> + <Col span={24} className="sql"> + <Form.Item label={'sql'}> + {getFieldDecorator('sql', { + initialValue: verify.script || defaultscript, + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + 'sql!' + } + ] + })(<CodeMirror />)} + </Form.Item> + </Col> + </Row> + </Form> + </TabPane> : null} + <TabPane tab="淇℃伅鎻愮ず" key="7"> + <Form {...formItemLayout}> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> S </span> + <Button onClick={() => {this.showError('S')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> Y </span> + <Button onClick={() => {this.showError('Y')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> N </span> + <Button onClick={() => {this.showError('N')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> F </span> + <Button onClick={() => {this.showError('F')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> E </span> + <Button onClick={() => {this.showError('E')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> NM </span> + <Button onClick={() => {this.showError('NM')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> -1 </span> + 涓嶆彁绀� + </Form.Item> + </Col> + </Row> + </Form> + </TabPane> + </Tabs> + </div> + ) + } +} + +export default Form.create()(VerifyCard) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyexcelout/index.scss b/src/menu/actioncomponent/verifyexcelout/index.scss new file mode 100644 index 0000000..94b67c9 --- /dev/null +++ b/src/menu/actioncomponent/verifyexcelout/index.scss @@ -0,0 +1,84 @@ +.verify-card-box { + .ant-tabs-nav-scroll { + text-align: center; + } + .ant-tabs-content { + min-height: 40vh; + } + table tr td { + word-wrap: break-word; + word-break: break-word; + } + .ant-input-number { + width: 100%; + } + .count-tip { + position: absolute; + top: 0px; + color: #1890ff; + font-size: 12px; + } + .verify-form { + .sql { + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + padding-top: 4px; + } + .CodeMirror { + height: 350px; + } + } + .sqlfield { + .ant-form-item { + margin-bottom: 5px; + } + .ant-form-item-control { + line-height: 24px; + } + .ant-form-item-label { + line-height: 25px; + } + .ant-form-item-children { + line-height: 22px; + } + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + } + } + .add { + padding-top: 4px; + } + } + .custom-table .ant-empty { + margin: 20px 8px!important; + } + .errorval { + display: inline-block; + width: 30px; + } + .operation-btn { + display: inline-block; + font-size: 16px; + padding: 0 5px; + cursor: pointer; + } +} +#verify-excelout-box-tab { + .ant-tabs-tabpane { + position: relative; + .excel-col-add { + position: relative; + float: right; + right: -9px; + margin-right: 10px; + top: -5px; + z-index: 1; + } + } +} \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyprint/editable/index.jsx b/src/menu/actioncomponent/verifyprint/editable/index.jsx new file mode 100644 index 0000000..cafd233 --- /dev/null +++ b/src/menu/actioncomponent/verifyprint/editable/index.jsx @@ -0,0 +1,239 @@ +import React, {Component} from 'react' +import { Table, Input, Popconfirm, Form, Icon } from 'antd' +import Utils from '@/utils/utils.js' +import './index.scss' + +const EditableContext = React.createContext() + +const EditableRow = ({ form, index, ...props }) => ( + <EditableContext.Provider value={form}> + <tr {...props} /> + </EditableContext.Provider> +) + +const EditableFormRow = Form.create()(EditableRow) + +class EditableCell extends Component { + state = { + editing: false + } + + toggleEdit = () => { + const editing = !this.state.editing + this.setState({ editing }, () => { + if (editing && this.input && this.input.select) { + this.input.select() + } else if (editing && this.input && this.input.focus) { + this.input.focus() + } + }) + } + + save = e => { + const { record, handleSave } = this.props + this.form.validateFields((error, values) => { + handleSave({ ...record, ...values }) + if (error && error[e.currentTarget.id]) { + return + } + this.toggleEdit() + }) + } + + renderCell = form => { + this.form = form + const { children, dataIndex, record } = this.props + const { editing } = this.state + + return editing ? ( + <Form.Item style={{ margin: 0 }}> + {form.getFieldDecorator(dataIndex, { + rules: [ + { + required: true, + message: 'NOT NULL.', + }, + ], + initialValue: record[dataIndex] + })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)} + </Form.Item> + ) : ( + <div + className="editable-cell-value-wrap" + onClick={this.toggleEdit} + > + {children} + </div> + ) + } + + render() { + const { + editable, + dataIndex, + title, + record, + index, + handleSave, + children, + ...restProps + } = this.props + return ( + <td {...restProps}> + {editable ? ( + <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer> + ) : ( + children + )} + </td> + ) + } +} + +class EditTable extends Component { + constructor(props) { + super(props) + + let columns = [ + { + title: 'Value', + dataIndex: 'Value', + width: '40%', + editable: true + }, + { + title: 'Text', + dataIndex: 'Text', + width: '40%', + editable: true + }, + { + title: '鎿嶄綔', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + this.state.dataSource.length >= 1 ? ( + <div> + <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span> + <Popconfirm + title={props.dict['header.form.query.delete']} + okText={props.dict['model.confirm']} + cancelText={props.dict['model.cancel']} + onConfirm={() => this.handleDelete(record.key) + }> + <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> + </Popconfirm> + </div> + ) : null, + } + ] + + this.state = { + columns: columns, + dataSource: props.data, + count: props.data.length, + linkSubFields: props.linkSubFields + } + } + + handleUpDown = (record, direction) => { + const { dataSource } = this.state + let index = 0 + + let _data = dataSource.filter((item, i) => { + if (item.key === record.key) { + index = i + } + + return item.key !== record.key + }) + if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) { + return + } + + if (direction === 'up') { + _data.splice(index - 1, 0, record) + } else { + _data.splice(index + 1, 0, record) + } + + this.setState({ + dataSource: _data + }) + } + + handleDelete = key => { + const dataSource = [...this.state.dataSource] + this.setState({ dataSource: dataSource.filter(item => item.key !== key) }) + } + + handleAdd = () => { + const { count, dataSource } = this.state + const newData = { + key: Utils.getuuid(), + Value: `${count}`, + Text: `${count}` + } + + this.setState({ + dataSource: [...dataSource, newData], + count: count + 1 + }) + } + + handleSave = row => { + const newData = [...this.state.dataSource] + const index = newData.findIndex(item => row.key === item.key) + const item = newData[index] + newData.splice(index, 1, { + ...item, + ...row + }) + this.setState({ dataSource: newData }) + } + + UNSAFE_componentWillReceiveProps () { + + } + + render() { + const { dataSource } = this.state + const components = { + body: { + row: EditableFormRow, + cell: EditableCell + } + } + const columns = this.state.columns.map(col => { + if (!col.editable) { + return col + } + return { + ...col, + onCell: record => ({ + record, + editable: col.editable, + dataIndex: col.dataIndex, + title: col.title, + handleSave: this.handleSave, + }) + } + }) + return ( + <div className="print-verify-edit-table"> + <Icon className="add-row" type="plus" onClick={this.handleAdd} /> + <Table + components={components} + rowClassName={() => 'editable-row'} + bordered + dataSource={dataSource} + columns={columns} + pagination={false} + /> + </div> + ) + } +} + +export default EditTable \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyprint/editable/index.scss b/src/menu/actioncomponent/verifyprint/editable/index.scss new file mode 100644 index 0000000..e353a37 --- /dev/null +++ b/src/menu/actioncomponent/verifyprint/editable/index.scss @@ -0,0 +1,51 @@ +.print-verify-edit-table { + margin: 10px 20px; + .add-row { + position: absolute; + z-index: 1; + right: 35px; + top: -30px; + padding: 10px; + font-size: 20px; + color: #26C281; + } + .ant-table-thead > tr > th { + padding: 10px 16px; + } + .ant-table-tbody > tr > td { + padding: 0px 16px; + } + .editable-cell-value-wrap { + cursor: pointer; + height: 40px; + width: 500px; + display: table-cell; + vertical-align: middle; + word-wrap: break-word; + word-break: break-word; + .ant-input { + height: 30px; + padding: 0 11px; + } + } + .ant-form-item-control-wrapper { + width: 100%; + } + .ant-table-placeholder { + padding: 5px 16px; + .ant-empty-normal { + margin: 0; + } + } + .operation-btn { + margin-right: 10px; + cursor: pointer; + } + .ant-table-content { + .ant-table-placeholder { + .ant-empty.ant-empty-normal { + margin: 50px 8px; + } + } + } +} diff --git a/src/menu/actioncomponent/verifyprint/index.jsx b/src/menu/actioncomponent/verifyprint/index.jsx new file mode 100644 index 0000000..23e1582 --- /dev/null +++ b/src/menu/actioncomponent/verifyprint/index.jsx @@ -0,0 +1,449 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import Utils from '@/utils/utils.js' +import CodeMirror from '@/templates/zshare/codemirror' +import EditTable from './editable' + +import './index.scss' + +const { TabPane } = Tabs + +class VerifyCard extends Component { + static propTpyes = { + floor: PropTypes.any, // 鏄惁涓哄瓙琛� + btnTab: PropTypes.any, // 琛ㄥ崟鏍囩椤碉紙鎸夐挳锛夊弬鏁� + config: PropTypes.any, // 琛ㄥ崟鏍囩椤靛弬鏁� + dict: PropTypes.object, // 瀛楀吀椤� + card: PropTypes.object, + columns: PropTypes.array + } + + state = { + verify: {}, + templates: [], + selectimg: '', + printMode: 'normal' + } + + UNSAFE_componentWillMount() { + let _verify = this.props.card.verify || {} + + _verify.Template = _verify.Template || '' + _verify.printerTypeList = _verify.printerTypeList || [] + _verify.linkType = _verify.linkType || 'system' + _verify.printMode = _verify.printMode || 'normal' + + this.setState({ + verify: _verify, + linkType: _verify.linkType, + printMode: _verify.printMode, + printFunc: _verify.printFunc || '// Function(data, form, printer, notification) data-鎵撳嵃鏁版嵁鍒楄〃锛宖orm-琛ㄥ崟淇℃伅锛堜笉瀛樺湪鏃朵负{}锛夛紝printer-鎵撳嵃璁剧疆锛宯otification-淇℃伅鎻愮ず鎺т欢' + }) + } + + componentDidMount() { + let _sql = `select PrintTempNO,Images,PrintTempNO+PrintTempName as PN from sPrintTemplate + where appkey= @appkey@ and Deleted=0 + union select ID,Images,a.PrintTempNO+PrintTempName as PN + from (select * from sPrintTemplate where appkey= '' and Deleted=0 ) a + left join (select PrintTempNO from sPrintTemplate where appkey= @appkey@ and Deleted=0 ) b + on a.PrintTempNO=b.PrintTempNO + left join (select Srcid from sPrintTemplate_Log where appkey='' and apicode= @appkey@ and Deleted=0 ) c + on a.ID=c.Srcid where b.PrintTempNO is null and c.Srcid is null` + + let param = { + func: 'sPC_Get_SelectedList', + LText: Utils.formatOptions(_sql), + obj_name: 'data', + arr_field: 'PN,PrintTempNO,Images' + } + + param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + param.secretkey = Utils.encrypt(param.LText, param.timestamp) + + param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) // 浜戠鏁版嵁楠岃瘉 + + Api.getSystemConfig(param).then(res => { + if (res.status) { + let temps = res.data.map(temp => { + return { + value: temp.PrintTempNO, + text: temp.PN, + img: temp.Images + } + }) + + let Template = this.state.verify.Template + let selectimg = '' + let selectTemp = temps.filter(temp => temp.value === Template)[0] + + if (!selectTemp) { + Template = '' + } else { + selectimg = selectTemp.img + } + + this.setState({ + selectimg: selectimg, + templates: temps, + verify: { + ...this.state.verify, + Template: Template + } + }) + } else { + notification.warning({ + top: 92, + message: res.message, + duration: 5 + }) + } + }) + } + + showError = (errorType) => { + if (errorType === 'S') { + notification.success({ + top: 92, + message: '鎵ц鎴愬姛锛�', + duration: 2 + }) + } else if (errorType === 'Y') { + Modal.success({ + title: '鎵ц鎴愬姛锛�' + }) + } else if (errorType === 'F') { + notification.error({ + className: 'notification-custom-error', + top: 92, + message: '鎵ц澶辫触锛�', + duration: 10 + }) + } else if (errorType === 'N') { + notification.error({ + top: 92, + message: '鎵ц澶辫触锛�', + duration: 10 + }) + } else if (errorType === 'E') { + Modal.error({ + title: '鎵ц澶辫触锛�' + }) + } else if (errorType === 'NM') { + message.error('鎵ц澶辫触锛�') + } + } + + timeChange = (val, type) => { + const { verify } = this.state + + this.setState({ + verify: {...verify, [type]: val} + }) + } + + changeTemplate = (val) => { + const { templates } = this.state + + let temp = templates.filter(temp => temp.value === val)[0] + + this.setState({ + selectimg: temp.img + }) + } + + handleConfirm = () => { + const { verify } = this.state + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let _verify = {...verify, ...values} + + if (this.refs.editTable && this.refs.editTable.state) { + let printTypes = this.refs.editTable.state.dataSource + + let emptys = printTypes.filter(item => !item.Value || !item.Text) + let valMap = new Map() + let isvalid = true + + printTypes.forEach(item => { + if (valMap.has(item.Value)) { + isvalid = false + } else { + valMap.set(item.Value, item.Text) + } + }) + + if (emptys.length > 0) { + notification.warning({ + top: 92, + message: '鎵撳嵃绫诲瀷琛ㄦ牸涓璙alue銆乀ext瀛楁涓嶅彲涓虹┖!', + duration: 5 + }) + return + } else if (!isvalid) { + notification.warning({ + top: 92, + message: '鎵撳嵃绫诲瀷琛ㄦ牸涓璙alue瀛楁涓嶅彲閲嶅!', + duration: 5 + }) + return + } + + _verify.printerTypeList = printTypes + } + + resolve(_verify) + } else { + notification.warning({ + top: 92, + message: '閾炬帴鍦板潃涓庢墦鍗版ā鏉夸笉鍙负绌�!', + duration: 5 + }) + } + }) + }) + } + + changePrintMode = (e) => { + let value = e.target.value + + this.setState({ + printMode: value + }) + } + + changeLinkType = (e) => { + let value = e.target.value + + this.setState({ + linkType: value + }, () => { + if (value === 'system') { + this.props.form.setFieldsValue({ + linkUrl: '127.0.0.1:13529' + }) + } + }) + } + + render() { + const { getFieldDecorator } = this.props.form + + const { verify, linkType, printMode, printFunc } = this.state + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <div id="verify-card-box-tab"> + <Tabs defaultActiveKey="1" className="verify-card-print-box" onChange={this.tabchange}> + <TabPane tab="鎵撳嵃楠岃瘉" key="1"> + <Form {...formItemLayout}> + <Row gutter={24}> + <Col span={8}> + <Form.Item label={'鎵撳嵃妯″紡'}> + {getFieldDecorator('printMode', { + initialValue: printMode || 'normal' + })( + <Radio.Group onChange={this.changePrintMode}> + <Radio value="normal">鏍囧噯</Radio> + <Radio value="custom">鑷畾涔�</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'閾炬帴绫诲瀷'}> + {getFieldDecorator('linkType', { + initialValue: linkType || 'system' + })( + <Radio.Group onChange={this.changeLinkType}> + <Radio value="system">绯荤粺</Radio> + <Radio value="custom">鑷畾涔�</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'閾炬帴鍦板潃'}> + {getFieldDecorator('linkUrl', { + initialValue: verify.linkUrl || '127.0.0.1:13529', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '閾炬帴鍦板潃!' + } + ] + })(<Input placeholder="" autoComplete="off" disabled={linkType === 'system'} />)} + </Form.Item> + </Col> + {printMode === 'custom' ? <Col span={24}> + <Form.Item label={'澶勭悊鍑芥暟'} className="printFunc"> + {getFieldDecorator('printFunc', { + initialValue: printFunc || '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '澶勭悊鍑芥暟!' + } + ] + })( + <CodeMirror mode="text/javascript"/> + )} + </Form.Item> + </Col> : null} + {printMode === 'normal' ? <Col span={8}> + <Form.Item label={'鎵撳嵃妯℃澘'}> + {getFieldDecorator('Template', { + initialValue: verify.Template || '', + rules: [ + { + required: true, + message: this.props.dict['form.required.select'] + '鎵撳嵃妯℃澘!' + } + ] + })( + <Select dropdownClassName="print-template-setting" onChange={this.changeTemplate}> + {this.state.templates.map((option, key) => + <Select.Option id={key} key={key} value={option.value}> + {option.text} + </Select.Option> + )} + </Select> + )} + </Form.Item> + </Col> : null } + {printMode === 'normal' ? <Col span={8} offset={8}> + <img className="legend" src={this.state.selectimg} alt=""/> + </Col> : null } + </Row> + </Form> + </TabPane> + <TabPane tab={ + <span> + 鎵撳嵃绫诲瀷 + {verify.printerTypeList.length ? <span className="count-tip">{verify.printerTypeList.length}</span> : null} + </span> + } key="2"> + <Form {...formItemLayout}> + <Row gutter={24}> + <Col span={24} className="print-tip"> + <Form.Item label={'鎻愮ず'}> + 濡傛灉姝ゆ寜閽秹鍙婂绉嶆暟鎹被鍨嬬殑鎵撳嵃锛岄渶瑕佽缃笉鍚岀殑鎵撳嵃鏈烘椂锛岃娣诲姞鎵撳嵃绫诲瀷鎺у埗淇℃伅锛岀敤鎴峰湪鑷畾涔夎缃腑锛屽彲鏍规嵁鎵撳嵃绫诲瀷璁剧疆瀵瑰簲鐨勬墦鍗版満銆� + 鎵撳嵃鏃讹紝鏁版嵁鐨勬墦鍗扮被鍨嬪彇鍐充簬杩斿洖鍊硷紙鍐呴儴鎴栧閮ㄦ帴鍙o級涓殑 printType 瀛楁銆� + 娉細杩斿洖鍊间腑鐨� printCount銆乼emplateID 瀛楁锛屽彲鍒嗗埆鎺у埗鎵撳嵃鏁伴噺鍜屾墦鍗版ā鏉裤�� + </Form.Item> + </Col> + <Col span={24}> + <EditTable data={verify.printerTypeList} dict={this.props.dict} ref="editTable"/> + </Col> + </Row> + </Form> + </TabPane> + <TabPane tab="淇℃伅鎻愮ず" key="7"> + <Form {...formItemLayout}> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> S </span> + <Button onClick={() => {this.showError('S')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> Y </span> + <Button onClick={() => {this.showError('Y')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> N </span> + <Button onClick={() => {this.showError('N')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> F </span> + <Button onClick={() => {this.showError('F')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={'鍋滅暀鏃堕棿'}> + <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} /> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> E </span> + <Button onClick={() => {this.showError('E')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> NM </span> + <Button onClick={() => {this.showError('NM')}} type="primary" size="small"> + 鏌ョ湅 + </Button> + </Form.Item> + </Col> + </Row> + <Row gutter={24}> + <Col offset={6} span={6}> + <Form.Item label={'鎻愮ず缂栫爜'}> + <span className="errorval"> -1 </span> + 涓嶆彁绀� + </Form.Item> + </Col> + </Row> + </Form> + </TabPane> + </Tabs> + </div> + ) + } +} + +export default Form.create()(VerifyCard) \ No newline at end of file diff --git a/src/menu/actioncomponent/verifyprint/index.scss b/src/menu/actioncomponent/verifyprint/index.scss new file mode 100644 index 0000000..1da8ed1 --- /dev/null +++ b/src/menu/actioncomponent/verifyprint/index.scss @@ -0,0 +1,68 @@ +.verify-card-print-box { + .ant-tabs-nav-scroll { + text-align: center; + } + .ant-tabs-content { + min-height: 40vh; + .ant-form-item { + margin-bottom: 10px; + } + } + .ant-input-disabled { + color: rgba(0, 0, 0, 0.65); + cursor: default; + } + .errorval { + display: inline-block; + width: 30px; + } + .operation-btn { + display: inline-block; + font-size: 16px; + padding: 0 5px; + cursor: pointer; + } + .legend { + width: 100%; + margin-bottom: 25px; + margin-left: -2px; + box-shadow: 0px 0px 2px #bcbcbc; + } + .printFunc { + .ant-form-item-label { + width: 10.7%; + } + .ant-form-item-control-wrapper { + width: 89.3%; + } + } + .code-mirror-area { + .CodeMirror { + height: calc(100vh - 360px); + } + } + .print-tip { + margin-bottom: 25px; + .ant-form-item-label { + width: 8.5%; + line-height: 25px; + } + .ant-form-item-control-wrapper { + width: 91.5%; + .ant-form-item-children { + line-height: 25px; + } + } + } + .count-tip { + position: absolute; + top: 0px; + color: #1890ff; + font-size: 12px; + } +} +.print-template-setting { + .ant-select-dropdown-menu-item { + white-space: normal; + } +} \ No newline at end of file diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx index 88bbd27..cf3b9d1 100644 --- a/src/menu/components/chart/antv-bar/index.jsx +++ b/src/menu/components/chart/antv-bar/index.jsx @@ -1,227 +1,552 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import { is, fromJS } from 'immutable' -import { InputItem, Icon, Checkbox, List, Button } from 'antd-mobile' -// import { createForm } from 'rc-form' +import { Chart } from '@antv/g2' +import DataSet from '@antv/data-set' + +import asyncComponent from '@/utils/asyncComponent' import zhCN from '@/locales/zh-CN/mob.js' import enUS from '@/locales/en-US/mob.js' -import Utils from '@/utils/utils.js' -import ContentUpdate from '@/mob/contupdate' -import mklogo from '@/assets/mobimg/mklogo.png' +// import ChartCompileForm from './chartcompile' import './index.scss' -const CheckboxItem = Checkbox.CheckboxItem +const SettingComponent = asyncComponent(() => import('@/menu/datasourcecomponent')) +const SearchComponent = asyncComponent(() => import('@/menu/searchcomponent')) +const ActionComponent = asyncComponent(() => import('@/menu/actioncomponent')) -class MobLogin extends Component { +class antvBarLineChart extends Component { static propTpyes = { + config: PropTypes.object, card: PropTypes.object, editId: PropTypes.any, triggerEdit: PropTypes.func, updateConfig: PropTypes.func, - onDoubleClick: PropTypes.func } state = { dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, - rember: true, - param: { - type: 'login', - subtype: 'mob-login-1', - box: { uuid: Utils.getuuid(), eleType: 'box', style: {color: '#ffffff', backgroundImage: 'linear-gradient(#378DBE, #46C29E, #48A9D6)'}}, - logo: { uuid: Utils.getuuid(), eleType: 'img', content: mklogo, style: {marginTop: '17vh', marginBottom: '15px'} }, - title: { uuid: Utils.getuuid(), eleType: 'text', content: '鏄庣鍟嗕笟鏅鸿兘寮�鏀惧钩鍙�', style: {fontSize: '20px', fontWeight: 'bold', color: '#ffffff', textAlign: 'center', marginTop: '15px', marginBottom: '30px'}}, - login: { uuid: Utils.getuuid(), eleType: 'button', content: '鐧诲綍', style: {fontSize: '18px', color: '#ffffff', textAlign: 'center', lineHeight: 2.4, borderRadius: '25px', marginBottom: '15vh'}}, - copyright: { uuid: Utils.getuuid(), eleType: 'textarea', content: 'Copyright漏2017 鎵�鏈夌浉鍏崇増鏉冨綊 鍖椾含鏄庣鏅崕淇℃伅鎶�鏈湁闄愬叕鍙�', style: {fontSize: '12px', color: '#ffffff', textAlign: 'center'} } - } + card: null, + visible: true } UNSAFE_componentWillMount () { - const { card } = this.props + const { card, config } = this.props + console.log(config) if (card.isNew) { - // this.props.updateConfig({...param, ...card}) + let _card = { + uuid: card.uuid, + type: card.type, + subtype: card.subtype, + setting: {span: 12, height: 400}, + columns: [], + scripts: [], + search: [], + action: [], + plot: {type: card.type, Xaxis: '', Yaxis: null} + } + this.setState({ + card: _card + }) + this.props.updateConfig(_card) + } else { + this.setState({ + card: fromJS(card).toJS() + }) } + } + + componentDidMount () { + this.viewrender() + } + + UNSAFE_componentWillReceiveProps (nextProps) { + if (!is(fromJS(this.props.plot), fromJS(nextProps.plot))) { + this.setState({}, () => { + this.viewrender() + }) + } + } + + getdata = (X_axis, Y_axis) => { + let data = [] + let xdata = ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩'] + let point = 7 + + for (let i = 0; i < point; i++) { + let item = {} + + item[X_axis] = xdata[i] + + if (typeof(Y_axis) === 'string') { + item[Y_axis] = Math.floor(Math.random() * 5 * (i + 1)) + i + } else { + Y_axis.forEach(y => { + item[y] = Math.floor(Math.random() * 5 * (i + 1)) + i + }) + } + + data.push(item) + } + + return data + } + + viewrender = () => { + const { card } = this.state + + if (card.plot.type === 'line') { + this.linerender() + } else if (card.plot.type === 'bar') { + this.barrender() + } + } + + linerender = () => { + const { plot, config } = this.props + + let transfield = {} + config.columns.forEach(col => { + if (col.field) { + transfield[col.field] = col.label + } + }) + + let X_axis = plot.Xaxis || 'x' + let Y_axis = plot.Yaxis || ['y'] + + let data = this.getdata(X_axis, Y_axis) + + if (plot.enabled !== 'true') { + const ds = new DataSet() + const dv = ds.createView().source(data) + + dv.transform({ + type: 'fold', + fields: [...Y_axis], + key: 'key', + value: 'value' + }) + + if (plot.Xaxis) { + dv.transform({ + type: 'map', + callback(row) { + row.key = transfield[row.key] + return row + }, + }) + } + + const chart = new Chart({ + container: plot.uuid, + autoFit: true, + height: plot.height || 400 + }) + + chart.data(dv.rows) + + if (plot.coordinate !== 'polar') { + chart.scale(X_axis, { + range: [0, 1] + }) + } + chart.scale('value', { + nice: true + }) + + if (!plot.legend || plot.legend === 'hidden') { + chart.legend(false) + } else { + chart.legend({ + position: plot.legend + }) + } + + if (plot.tooltip !== 'true') { + chart.tooltip(false) + } else { + chart.tooltip({ + shared: true + }) + } + + if (plot.transpose === 'true') { + chart.coordinate().transpose() + } + + if (plot.coordinate === 'polar') { + chart.coordinate('polar', { + innerRadius: 0.1, + radius: 0.8 + }) + } + + let _chart = chart + .line() + .position(`${X_axis}*value`) + .color('key') + .shape(plot.shape || 'smooth') + + if (plot.label === 'true') { + _chart.label('value') + } + + if (plot.point === 'true') { + chart + .point() + .position(`${X_axis}*value`) + .color('key') + .size(3) + .shape('circle') + } + chart.render() + } else { + this.customrender(data, transfield) + } + } + + customrender = (data, transfield) => { + const { plot } = this.props + + let barfields = [] + let fields = [] + let legends = [] + + plot.customs.forEach(item => { + item.name = transfield[item.field] || item.field + if (item.axis === 'left') { + item.index = 0 + } else if (item.axis === 'right') { + item.index = 1 + } else { + item.index = 2 + } + + if (item.chartType === 'bar') { + barfields.push(item.field) + fields.unshift(item) + } else { + fields.push(item) + } + + legends.push({ + value: item.name, + name: item.name, + marker: { symbol: item.chartType === 'bar' ? 'square' : 'hyphen', style: { stroke: item.color,fill: item.color, r: 5, lineWidth: 2 } } + }) + }) + + fields.sort((a, b) => a.index - b.index) + + const ds = new DataSet() + const dv = ds.createView().source(data) + dv.transform({ + type: 'map', + callback(row) { + fields.forEach(line => { + row[line.name] = row[line.field] + }) + return row + } + }) + + const chart = new Chart({ + container: plot.uuid, + autoFit: true, + height: plot.height || 400 + }) + + chart.data(dv.rows) + + if (plot.coordinate !== 'polar' && barfields.length === 0) { + chart.scale(plot.Xaxis, { + range: [0, 1] + }) + } + + if (!plot.legend || plot.legend === 'hidden') { + chart.legend(false) + } else { + chart.legend({ + custom: true, + position: plot.legend, + items: legends, + }) + } + + if (plot.tooltip !== 'true') { + chart.tooltip(false) + } else { + chart.tooltip({ + shared: true + }) + } + + if (plot.transpose === 'true') { + chart.coordinate().transpose() + } + + if (plot.coordinate === 'polar') { + chart.coordinate('polar', { + innerRadius: 0.1, + radius: 0.8 + }) + } + + chart.scale({ + nice: true + }) + + fields.forEach((item, i) => { + if (i === 0) { + chart.axis(item.name, { + grid: {}, + title: {}, + label: {} + }) + } else if (i === 1 && item.axis !== 'unset') { + chart.axis(item.name, { + grid: null, + title: {}, + label: {} + }) + } else { + chart.axis(item.name, { + grid: null, + title: null, + label: null + }) + } + + if (item.chartType === 'bar') { + let _chart = chart + .interval() + .position(`${plot.Xaxis}*${item.name}`) + .color(item.color) + .shape(item.shape) + + if (item.label === 'true') { + _chart.label(item.name) + } + } else if (item.chartType === 'line') { + let _chart = chart + .line() + .position(`${plot.Xaxis}*${item.name}`) + .color(item.color) + .shape(item.shape) + + if (item.label === 'true') { + _chart.label(item.name) + } + + if (plot.point === 'true') { + chart + .point() + .position(`${plot.Xaxis}*${item.name}`) + .color(item.color) + .size(3) + .shape('circle') + } + } + }) + + chart.render() + } + + barrender = () => { + const { card } = this.state + + let plot = {...card.plot, height: card.setting.height - 70} + + let transfield = {} + card.columns.forEach(col => { + if (col.field) { + transfield[col.field] = col.label + } + }) + let X_axis = plot.Xaxis || 'x' + let Y_axis = plot.Yaxis || ['y'] + + let data = this.getdata(X_axis, Y_axis) + console.log(plot) + console.log(data) + + if (plot.enabled !== 'true') { + const ds = new DataSet() + const dv = ds.createView().source(data) + + dv.transform({ + type: 'fold', + fields: [...Y_axis], + key: 'key', + value: 'value' + }) + + if (plot.Xaxis) { + dv.transform({ + type: 'map', + callback(row) { + row.key = transfield[row.key] + return row + }, + }) + } + + const chart = new Chart({ + container: card.uuid, + autoFit: true, + height: plot.height || 400 + }) + + console.log(dv.rows) + chart.data(dv.rows) + + chart.scale('value', { + nice: true + }) + + if (!plot.legend || plot.legend === 'hidden') { + chart.legend(false) + } else { + chart.legend({ + position: plot.legend + }) + } + + if (plot.tooltip !== 'true') { + chart.tooltip(false) + } else { + chart.tooltip({ + shared: true + }) + } + + if (plot.transpose === 'true') { + chart.coordinate().transpose() + } + + if (plot.coordinate === 'polar') { + chart.coordinate('polar', { + innerRadius: 0.1, + radius: 0.8 + }) + } + + if (plot.adjust !== 'stack') { + let _chart = chart + .interval() + .position(`${X_axis}*value`) + .color('key') + .adjust([ + { + type: 'dodge', + marginRatio: 0 + } + ]) + .shape(plot.shape || 'rect') + + if (plot.label === 'true') { + _chart.label('value') + } + } else if (plot.adjust === 'stack') { + let _chart = chart + .interval() + .position(`${X_axis}*value`) + .color('key') + .adjust('stack') + .shape(plot.shape || 'rect') + + if (plot.label === 'true') { + _chart.label('value') + } + } + + chart.render() + } else { + this.customrender(data, transfield) + } + } + + plotChange = (_plot) => { + const { config } = this.props + + if (_plot.datatype === 'statistics') { + _plot.Yaxis = [_plot.InfoValue] + } + + let _charts = fromJS(config.charts).toJS() + + _charts = _charts.map(item => { + if (item.uuid === _plot.uuid) { + if (!is(fromJS(item), fromJS(_plot))) { + let _element = document.getElementById(_plot.uuid) + if (_element) { + _element.innerHTML = '' + } + } + return _plot + } + return item + }) + + this.props.plotchange({...config, charts: _charts}) } shouldComponentUpdate (nextProps, nextState) { return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)) } - onChange = (e) => { - const { rember } = this.state - e.stopPropagation() - + updateComponent = (component) => { this.setState({ - rember: !rember + card: component }) + this.props.updateConfig(component) } - onChangeLang = (value) => { - this.setState({ - lang: value - }) - } - - editLogo = (e) => { - const { card } = this.props - e.stopPropagation() - let element = { - ...fromJS(card.logo.style).toJS(), - componentId: card.uuid, - uuid: card.logo.uuid, - items: ['margin'] - } - this.props.triggerEdit(element) - } - - editTitle = (e) => { - const { card } = this.props - e.stopPropagation() - let element = { - ...fromJS(card.title.style).toJS(), - componentId: card.uuid, - uuid: card.title.uuid, - items: ['font', 'margin'], - } - this.props.triggerEdit(element) - } - - editMsg = (e) => { - const { card } = this.props - e.stopPropagation() - let element = { - ...fromJS(card.copyright.style).toJS(), - componentId: card.uuid, - uuid: card.copyright.uuid, - items: ['font'], - } - this.props.triggerEdit(element) - } - - editLogin = (e) => { - const { card } = this.props - e.stopPropagation() - let element = { - ...fromJS(card.login.style).toJS(), - componentId: card.uuid, - uuid: card.login.uuid, - items: ['font', 'background', 'border', 'margin'] - } - this.props.triggerEdit(element) - } - - editBox = (e) => { - const { card } = this.props - e.stopPropagation() - let element = { - ...fromJS(card.box.style).toJS(), - componentId: card.uuid, - uuid: card.box.uuid, - items: ['font', 'padding', 'background'], - } - this.props.triggerEdit(element) - } - - updateContent = (card) => { - Object.keys(card).forEach(key => { - if (card[key] === null) { - delete card[key] - } - }) - this.props.updateConfig(card) - } - - render () { - const { card, editId } = this.props - // const { getFieldProps } = this.props.form - const { rember } = this.state - - if (!card.box) return null - - let logoStyle = card.logo && card.logo.style ? fromJS(card.logo.style).toJS() : null - if (logoStyle && logoStyle.marginTop && /vh$/ig.test(logoStyle.marginTop)) { - let percent = parseInt(logoStyle.marginTop) - logoStyle.marginTop = `calc(${(percent / 100) * 615}px)` - } - if (logoStyle && logoStyle.marginBottom && /vh$/ig.test(logoStyle.marginBottom)) { - let percent = parseInt(logoStyle.marginBottom) - logoStyle.marginBottom = `calc(${(percent / 100) * 625}px)` - } - - let titleStyle = card.title && card.title.style ? fromJS(card.title.style).toJS() : null - if (titleStyle && titleStyle.marginTop && /vh$/ig.test(titleStyle.marginTop)) { - let percent = parseInt(titleStyle.marginTop) - titleStyle.marginTop = `calc(${(percent / 100) * 615}px)` - } - if (titleStyle && titleStyle.marginBottom && /vh$/ig.test(titleStyle.marginBottom)) { - let percent = parseInt(titleStyle.marginBottom) - titleStyle.marginBottom = `calc(${(percent / 100) * 615}px)` - } - - let loginStyle = fromJS(card.login.style).toJS() - if (loginStyle.marginTop && /vh$/ig.test(loginStyle.marginTop)) { - let percent = parseInt(loginStyle.marginTop) - loginStyle.marginTop = `calc(${(percent / 100) * 615}px)` - } - if (loginStyle.marginBottom && /vh$/ig.test(loginStyle.marginBottom)) { - let percent = parseInt(loginStyle.marginBottom) - loginStyle.marginBottom = `calc(${(percent / 100) * 615}px)` - } + render() { + const { card } = this.state + const { config } = this.props return ( - <div className="mob-login-1" onClick={this.editBox} style={card.box.style}> - {card.logo ? <div className={'logo ' + (editId === card.logo.uuid ? 'editing' : '')} style={logoStyle} onClick={this.editLogo}> - <ContentUpdate element={card.logo} updateContent={(ele) => this.updateContent({...card, logo: ele})}/> - <img src={card.logo.content} alt=""/> - </div> : null} - {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}> - <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/> - {card.title.content} - </div> : null} - <InputItem - placeholder={"UserName"} - prefixListCls="mk-login-item am-list" - disabled={true} - > - <Icon type="check-circle-o" /> - </InputItem> - <InputItem - placeholder="Password" - prefixListCls="mk-login-item am-list" - type={'password'} - disabled={true} - > - <Icon type="check-circle" /> - </InputItem> - <div className="other-setting"> - <CheckboxItem checked={rember} onChange={this.onChange}> - <span onClick={this.onChange}>璁颁綇瀵嗙爜</span> - </CheckboxItem> - {/* <Picker data={langs} value={lang} cols={1} onChange={this.onChangeLang} className="forss"> - <List.Item>{lang}</List.Item> - </Picker> */} - <List.Item className="lang">涓枃绠�浣�</List.Item> - <div className="clear-both"></div> + <div className="line-chart-edit-box" style={{height: card.setting.height || 400}}> + <SettingComponent + config={{...card, tables: config.tables}} + MenuID={config.uuid} + tableFields={config.tableFields || []} + permFuncField={config.permFuncField || []} + updateConfig={this.updateComponent} + /> + <div className="chart-header"> + <span className="chart-title">{card.setting.title || ''}</span> + <SearchComponent + menu={{MenuID: config.uuid, MenuName: config.MenuName}} + config={card} + sysRoles={config.sysRoles} + optionLibs={null} + updatesearch={this.updateComponent} + /> </div> - <Button - type="primary" - className={'login ' + (editId === card.login.uuid ? 'editing' : '')} - onDoubleClick={() => this.props.doubleClickCard(card.login)} - style={loginStyle} - onClick={this.editLogin} - > - <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/> - {card.login.content} - </Button> - {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}> - <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/> - {card.copyright.content} - </div> : null} + <ActionComponent + menu={{ MenuID: config.uuid, MenuName: config.MenuName, MenuNo: config.MenuNo, fstMenuList: config.fstMenuList }} + config={card} + tabs={[]} + usefulFields={config.permFuncField || []} + // setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')} + updateaction={this.updateComponent} + /> + <div className="canvas" id={card.uuid}></div> + {/* <ChartCompileForm + plot={plot} + type={plot.chartType} + config={this.props.config} + dict={this.state.dict} + plotchange={this.plotChange} + /> */} </div> ) } } -// export default createForm()(MobLogin) -export default MobLogin \ No newline at end of file +export default antvBarLineChart \ No newline at end of file diff --git a/src/menu/components/chart/antv-bar/index.scss b/src/menu/components/chart/antv-bar/index.scss index 4ce0042..33e95af 100644 --- a/src/menu/components/chart/antv-bar/index.scss +++ b/src/menu/components/chart/antv-bar/index.scss @@ -1,192 +1,23 @@ -.mob-login-1 { +.line-chart-edit-box { position: relative; - width: 100%; - min-height: 100%; - overflow-x: hidden; - background-repeat: no-repeat; - background-size: cover; - background-position: center center; - border-top: 1px solid transparent; - - .logo { - position: relative; - font-size: 14px; - max-width: 280px; - min-height: 10px; - margin: 0 auto; - text-align: center; - line-height: 1.5; - border: 1px dotted transparent; - img { - max-width: 100%; - } - } - .logo.editing { - border: 1px solid #1890ff; - box-shadow: 0px 0px 2px #1890ff; - } - .logo:not(.editing):hover { - border-color: #535353; + margin-bottom: 30px; + border: 1px solid #e8e8e8; + + .canvas { + margin: 0px; + padding: 10px 15px; } - .plat-name { - position: relative; - max-width: 280px; - min-height: 10px; - margin: 0 auto; - margin-top: 15px; - margin-bottom: 30px; - text-align: center; - line-height: 1.5; - font-size: 20px; - color: #ffffff; - font-weight: bold; - letter-spacing: 0px; - border: 1px dotted transparent; - } - .plat-name.editing { - border: 1px solid #1890ff; - box-shadow: 0px 0px 2px #1890ff; - } - .plat-name:not(.editing):hover { - border-color: #535353; - } + .chart-header { + height: 50px; + border-bottom: 1px solid #e8e8e8; + overflow: hidden; - .mk-login-item.am-list-item { - position: relative; - z-index: 1; - width: 245px; - font-size: 14px; - max-width: 270px; - line-height: 1.5; - margin: 0 auto; - margin-bottom: 10px; - border-radius: 30px; - background-color: rgba(255, 255, 255, 0.3); - .am-input-label { - width: 30px; - color: inherit; - padding-top: 10px; - } - input { - color: inherit; - } - input::-webkit-input-placeholder { - color: inherit; - } - input:-moz-placeholder { - color: inherit; - } - input::-moz-placeholder { - color: inherit; - } - input:-ms-input-placeholder { - color: inherit; - } - - .am-input-control input:disabled { - background-color: transparent; - } - } - .am-list-item:not(:last-child) .am-list-line { - border: none; - } - .other-setting { - position: relative; - z-index: 1; - font-size: 14px; - width: 245px; - max-width: 270px; - line-height: 1.5; - margin: 0 auto; - margin-bottom: 10px; - .am-list-item { + .chart-title { + font-size: 16px; float: left; - background: transparent; - width: 50%; - padding: 0; - .am-list-thumb:first-child { - margin-right: 5px; - cursor: pointer; - - .am-checkbox-inner { - width: 18px; - height: 18px; - } - .am-checkbox-inner:after { - width: 5px; - height: 9px; - } - } - .am-list-line .am-list-content { - font-size: 14px; - color: inherit; - cursor: pointer; - } - .am-list-extra { - display: none; - } + line-height: 50px; + margin-left: 10px; } - - .am-list-item.lang { - float: right; - .am-list-line { - padding-right: 10px; - .am-list-content { - text-align: right; - cursor: default; - } - } - } - } - .am-button { - position: relative; - z-index: 1; - width: 245px; - max-width: 270px; - margin: 0 auto; - border: 1px dotted transparent; - overflow: visible; - letter-spacing: 0px; - background-repeat: no-repeat; - background-size: cover; - background-position: center center; - - span { - font-style: inherit; - font-weight: inherit; - } - } - .am-button:hover { - color: #fff; - border-color: #535353; - } - .company-msg { - max-width: 280px; - min-height: 10px; - margin: 0 auto; - font-size: 12px; - color: #fafafa; - text-align: center; - line-height: 1.5; - letter-spacing: 0px; - border: 1px dotted transparent; - } - .company-msg.editing { - border: 1px solid #1890ff; - box-shadow: 0px 0px 2px #1890ff; - } - .company-msg:not(.editing):hover { - border-color: #535353; } } -.am-picker-popup-wrap { - left: calc(50vw - 305px); - right: calc(50vw - 45px); - bottom: 54px; - overflow: hidden; -} -.clear-both { - float: none!important; - clear: both; -} \ No newline at end of file diff --git a/src/menu/datasourcecomponent/index.jsx b/src/menu/datasourcecomponent/index.jsx new file mode 100644 index 0000000..4c285ae --- /dev/null +++ b/src/menu/datasourcecomponent/index.jsx @@ -0,0 +1,93 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { Icon, Modal } from 'antd' + +import zhCN from '@/locales/zh-CN/model.js' +import enUS from '@/locales/en-US/model.js' +import VerifyCard from './verifycard' +import './index.scss' + +class DataSource extends Component { + static propTpyes = { + config: PropTypes.any, + MenuID: PropTypes.string, + tableFields: PropTypes.any, + permFuncField: PropTypes.any, + updateConfig: PropTypes.func + } + + state = { + dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + sourcelist: [], + visible: false, + loading: false, + setting: null + } + + UNSAFE_componentWillMount () { + const { config } = this.props + + this.setState({setting: fromJS(config.setting).toJS()}) + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)) + } + + editDataSource = () => { + this.setState({ + visible: true + }) + } + + verifySubmit = () => { + const { config } = this.props + + this.setState({loading: true}) + this.verifyRef.submitDataSource().then(res => { + + this.setState({loading: false, visible: false}) + this.props.updateConfig({...config, ...res}) + }, () => { + this.setState({loading: false}) + }) + } + + render () { + const { config } = this.props + const { visible, dict, loading } = this.state + + return ( + <div className="model-datasource"> + <Icon type="setting" onClick={() => this.editDataSource()} /> + <Modal + wrapClassName="model-datasource-verify-modal popview-modal" + title={'鏁版嵁婧愰厤缃�'} + visible={visible} + width={'75vw'} + maskClosable={false} + style={{minWidth: '900px', maxWidth: '1200px'}} + okText={dict['model.submit']} + cancelText={dict['model.cancel']} + onOk={this.verifySubmit} + confirmLoading={loading} + onCancel={() => { this.setState({ visible: false }) }} + destroyOnClose + > + <VerifyCard + dict={dict} + config={config} + tableFields={this.props.tableFields} + permFuncField={this.props.permFuncField} + menuId={this.props.config.uuid} + searches={config.search} + wrappedComponentRef={(inst) => this.verifyRef = inst} + /> + </Modal> + </div> + ) + } +} + +export default DataSource \ No newline at end of file diff --git a/src/menu/datasourcecomponent/index.scss b/src/menu/datasourcecomponent/index.scss new file mode 100644 index 0000000..c994031 --- /dev/null +++ b/src/menu/datasourcecomponent/index.scss @@ -0,0 +1,94 @@ +.model-datasource { + position: absolute; + right: 7px; + top: 5px; + z-index: 1; + + >.anticon-setting { + font-size: 18px; + padding: 10px; + } + + .model-input-group-wrapper { + padding: 0 20px; + display: inline-block; + width: 100%; + text-align: start; + vertical-align: top; + margin-bottom: 15px; + + .model-input-wrapper { + position: relative; + display: table; + width: 100%; + border-collapse: separate; + border-spacing: 0; + + .model-input-value { + display: table-cell; + width: 100%; + border: 1px solid #d9d9d9; + border-radius: 4px 0px 0px 4px; + overflow: hidden; + text-overflow:ellipsis; + white-space: nowrap; + padding: 2px 10px; + color: #ffffff; + } + + .model-input-group-addon { + display: table-cell; + width: 1px; + position: relative; + padding: 0 11px; + color: rgba(0, 0, 0, 0.65); + font-weight: normal; + font-size: 14px; + line-height: 1; + text-align: center; + background-color: #fafafa; + border: 1px solid #d9d9d9; + border-radius: 0px 4px 4px 0px; + white-space: nowrap; + } + + .model-input-insert { + display: table-cell; + width: 100%; + border: 1px dotted #d9d9d9; + border-radius: 4px; + text-align: center; + cursor: pointer; + + .anticon-plus { + padding: 6px; + font-size: 16px; + color: rgb(38, 194, 129); + } + } + } + .anticon-setting { + margin-right: 5px; + padding: 6px; + cursor: pointer; + } + .anticon-setting:hover { + color: #1890ff; + } + .anticon-close { + padding: 6px; + cursor: pointer; + } + .anticon-close:hover { + color: #ff4d4f; + } + } +} +.model-datasource-verify-modal { + .ant-modal { + top: 50px; + .ant-modal-body { + max-height: calc(100vh - 190px); + } + } +} \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/columnform/index.jsx b/src/menu/datasourcecomponent/verifycard/columnform/index.jsx new file mode 100644 index 0000000..c8ef7bb --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/columnform/index.jsx @@ -0,0 +1,145 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Select, Button, Input } from 'antd' +import './index.scss' + + +class UniqueForm extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + columnChange: PropTypes.func // 淇敼鍑芥暟 + } + + state = { + editItem: null // 缂栬緫鍏冪礌 + } + + edit = (record) => { + this.setState({ + editItem: record + }) + + this.props.form.setFieldsValue({ + label: record.label, + field: record.field, + datatype: record.datatype + }) + } + + + handleConfirm = () => { + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.state.editItem ? this.state.editItem.uuid : '' + + this.setState({ + editItem: null + }, () => { + this.props.columnChange(values) + }) + this.props.form.setFieldsValue({ + label: '', + field: '' + }) + } + }) + } + + render() { + const { getFieldDecorator } = this.props.form + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <Form {...formItemLayout} className="verify-form" id="verifycard1"> + <Row gutter={24}> + <Col span={7}> + <Form.Item label={'鍚嶇О'}> + {getFieldDecorator('label', { + initialValue: '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '鍚嶇О!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={'瀛楁'}> + {getFieldDecorator('field', { + initialValue: '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '瀛楁!' + } + ] + })(<Input placeholder="" autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={7}> + <Form.Item label={'鏁版嵁绫诲瀷'}> + {getFieldDecorator('datatype', { + initialValue: '', + rules: [ + { + required: true, + message: this.props.dict['form.required.select'] + '鏁版嵁绫诲瀷!' + } + ] + })( + <Select> + <Select.Option value="Nvarchar(50)"> Nvarchar(50) </Select.Option> + <Select.Option value="Nvarchar(100)"> Nvarchar(100) </Select.Option> + <Select.Option value="Nvarchar(512)"> Nvarchar(512) </Select.Option> + <Select.Option value="Nvarchar(1024)"> Nvarchar(1024) </Select.Option> + <Select.Option value="Nvarchar(2048)"> Nvarchar(2048) </Select.Option> + <Select.Option value="Nvarchar(max)"> Nvarchar(max) </Select.Option> + <Select.Option value="Int"> Int </Select.Option> + <Select.Option value="Decimal(18,0)"> Decimal(18,0) </Select.Option> + <Select.Option value="Decimal(18,1)"> Decimal(18,1) </Select.Option> + <Select.Option value="Decimal(18,2)"> Decimal(18,2) </Select.Option> + <Select.Option value="Decimal(18,3)"> Decimal(18,3) </Select.Option> + <Select.Option value="Decimal(18,4)"> Decimal(18,4) </Select.Option> + <Select.Option value="Decimal(18,5)"> Decimal(18,5) </Select.Option> + <Select.Option value="Decimal(18,6)"> Decimal(18,6) </Select.Option> + <Select.Option value="Decimal(18,7)"> Decimal(18,7) </Select.Option> + <Select.Option value="Decimal(18,8)"> Decimal(18,8) </Select.Option> + <Select.Option value="Decimal(18,9)"> Decimal(18,9) </Select.Option> + <Select.Option value="Decimal(18,10)"> Decimal(18,10) </Select.Option> + <Select.Option value="Decimal(18,11)"> Decimal(18,11) </Select.Option> + <Select.Option value="Decimal(18,12)"> Decimal(18,12) </Select.Option> + <Select.Option value="Decimal(18,13)"> Decimal(18,13) </Select.Option> + <Select.Option value="Decimal(18,14)"> Decimal(18,14) </Select.Option> + <Select.Option value="Decimal(18,15)"> Decimal(18,15) </Select.Option> + <Select.Option value="Decimal(18,16)"> Decimal(18,16) </Select.Option> + <Select.Option value="Decimal(18,17)"> Decimal(18,17) </Select.Option> + <Select.Option value="Decimal(18,18)"> Decimal(18,18) </Select.Option> + {/* <Select.Option value="date"> date </Select.Option> */} + </Select> + )} + </Form.Item> + </Col> + <Col span={3} className="add"> + <Button onClick={this.handleConfirm} type="primary" className="mk-green"> + 淇濆瓨 + </Button> + </Col> + </Row> + </Form> + ) + } +} + +export default Form.create()(UniqueForm) \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/columnform/index.scss b/src/menu/datasourcecomponent/verifycard/columnform/index.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/columnform/index.scss diff --git a/src/menu/datasourcecomponent/verifycard/customscript/index.jsx b/src/menu/datasourcecomponent/verifycard/customscript/index.jsx new file mode 100644 index 0000000..996e2ff --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/customscript/index.jsx @@ -0,0 +1,231 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Button, notification, Select } from 'antd' + +import Utils from '@/utils/utils.js' +import CodeMirror from '@/templates/zshare/codemirror' +import './index.scss' + +class CustomForm extends Component { + static propTpyes = { + type: PropTypes.string, // 鑿滃崟绫诲瀷 + dict: PropTypes.object, // 瀛楀吀椤� + setting: PropTypes.object, // 璁剧疆 + searches: PropTypes.array, // 鎼滅储鏉′欢 + swhere: PropTypes.string, // where鏉′欢 + arr_field: PropTypes.string, // 鍒楀瓧娈� + regoptions: PropTypes.array, // 姝e垯鏇挎崲 + systemScripts: PropTypes.array, // 绯荤粺鑴氭湰 + scriptSubmit: PropTypes.func, // 鑴氭湰楠岃瘉鍚庢彁浜� + scriptsChange: PropTypes.func // 鑴氭湰楠岃瘉 + } + + state = { + editItem: null, + loading: false, + usefulFields: '' + } + + UNSAFE_componentWillMount() { + const { searches } = this.props + + let _usefulFields = [] + searches.forEach(item => { + if (!item.field) return + + if (item.type === 'group') { + if (item.transfer === 'true') { + _usefulFields.push(item.field) + } + _usefulFields.push(item.datefield) + _usefulFields.push(item.datefield + '1') + } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) { + _usefulFields.push(item.field) + _usefulFields.push(item.field + '1') + } else if (_usefulFields.includes(item.field)) { + _usefulFields.push(item.field + '1') + } else { + _usefulFields.push(item.field) + } + }) + + this.setState({ + usefulFields: _usefulFields.join(', ') + }) + } + + edit = (record) => { + this.setState({ + editItem: record + }) + + this.props.form.setFieldsValue({ + sql: record.sql + }) + } + + handleCancel = () => { + this.setState({ + editItem: null + }) + this.props.form.setFieldsValue({ + sql: '' + }) + } + + handleConfirm = () => { + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values.uuid = this.state.editItem ? this.state.editItem.uuid : '' + + let _quot = values.sql.match(/'{1}/g) + let _lparen = values.sql.match(/\({1}/g) + let _rparen = values.sql.match(/\){1}/g) + + _quot = _quot ? _quot.length : 0 + _lparen = _lparen ? _lparen.length : 0 + _rparen = _rparen ? _rparen.length : 0 + + if (_quot % 2 !== 0) { + notification.warning({ + top: 92, + message: 'sql涓璡'蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + return + } else if (_lparen !== _rparen) { + notification.warning({ + top: 92, + message: 'sql涓�()蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + return + } else if (/--/ig.test(values.sql)) { + notification.warning({ + top: 92, + message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/', + duration: 5 + }) + return + } + + let error = Utils.verifySql(values.sql, 'customscript') + + if (error) { + notification.warning({ + top: 92, + message: 'sql涓笉鍙娇鐢�' + error, + duration: 5 + }) + return + } + + this.setState({loading: true}) + this.props.scriptsChange(values).then(() => { + this.setState({ + editItem: null, + loading: false + }) + this.props.form.setFieldsValue({ + sql: '' + }) + this.props.scriptSubmit(values) + }) + } + }) + } + + selectScript = (value, option) => { + let _sql = this.props.form.getFieldValue('sql') + if (_sql) { + _sql = _sql + ` + + ` + } + + _sql = _sql.replace(/\s{6}$/, '') + _sql = _sql + `/*${option.props.children}*/ + ` + _sql = _sql.replace(/\s{4}$/, '') + _sql = _sql + value + + this.props.form.setFieldsValue({ + sql: _sql + }) + } + + render() { + const { systemScripts, setting } = this.props + const { getFieldDecorator } = this.props.form + const { usefulFields } = this.state + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <Form {...formItemLayout} className="modal-menu-setting-script"> + <Row gutter={24}> + {setting.tableName ? <Col span={8}> + <Form.Item label={'琛ㄥ悕'} style={{whiteSpace: 'nowrap', margin: 0}}> + {setting.tableName} + </Form.Item> + </Col> : null} + <Col span={16}> + <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0}}> + ErrorCode, retmsg + </Form.Item> + </Col> + <Col span={24} className="sqlfield"> + <Form.Item label={'鍙敤瀛楁'}> + id, bid, loginuid, sessionuid, userid, appkey, time_id, calendarDate, calendarDate1{usefulFields ? ', ' + usefulFields : ''} + </Form.Item> + </Col> + <Col span={10}> + <Form.Item label={'蹇嵎娣诲姞'} style={{marginBottom: 0}}> + <Select + showSearch + filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} + onChange={this.selectScript} + > + {systemScripts.map((option, i) => + <Select.Option style={{whiteSpace: 'normal'}} key={i} value={option.value}>{option.name}</Select.Option> + )} + </Select> + </Form.Item> + </Col> + <Col span={6} className="add"> + <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginTop: 5, marginBottom: 15, marginLeft: 30}}> + 淇濆瓨 + </Button> + <Button onClick={this.handleCancel} style={{marginTop: 5, marginBottom: 15, marginLeft: 10}}> + 鍙栨秷 + </Button> + </Col> + <Col span={24} className="sql"> + <Form.Item label={'sql'}> + {getFieldDecorator('sql', { + initialValue: '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + 'sql!' + } + ] + })(<CodeMirror />)} + </Form.Item> + </Col> + </Row> + </Form> + ) + } +} + +export default Form.create()(CustomForm) \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/customscript/index.scss b/src/menu/datasourcecomponent/verifycard/customscript/index.scss new file mode 100644 index 0000000..2a1d2d8 --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/customscript/index.scss @@ -0,0 +1,34 @@ +.modal-menu-setting-script { + .sqlfield { + .ant-form-item { + margin-bottom: 5px; + } + .ant-form-item-control { + line-height: 24px; + } + .ant-form-item-label { + line-height: 25px; + } + .ant-form-item-children { + line-height: 22px; + } + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + } + } + .sql { + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + padding-top: 4px; + } + .CodeMirror { + height: 350px; + } + } +} \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/index.jsx b/src/menu/datasourcecomponent/verifycard/index.jsx new file mode 100644 index 0000000..19276e6 --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/index.jsx @@ -0,0 +1,551 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { fromJS } from 'immutable' +import { Form, Tabs, Table, Popconfirm, Icon, notification, Modal, Typography, Spin } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import Utils from '@/utils/utils.js' + +import asyncComponent from '@/utils/asyncComponent' +import ColForm from './columnform' +import CustomScriptsForm from './customscript' +import SettingForm from './settingform' +import SettingUtils from './utils' +import './index.scss' + +const { TabPane } = Tabs +const { Paragraph } = Typography + +const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent')) + +class VerifyCard extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + tableFields: PropTypes.any, // 鏁版嵁婧愪俊鎭� + permFuncField: PropTypes.any, // 鏁版嵁婧愪俊鎭� + config: PropTypes.object, // 鏁版嵁婧愪俊鎭� + menuId: PropTypes.string, // 鑿滃崟Id + searches: PropTypes.array, // 鎼滅储鏉′欢 + } + + state = { + columns: [], + activeKey: 'setting', + loading: false, + initsql: '', // sql楠岃瘉鏃跺彉閲忓0鏄庡強璧嬪�� + usefulfields: '', + defaultsql: '', // 榛樿Sql + systemScripts: [{ + name: '榛樿sql', + value: '' + }], + colColumns: [ + { + title: '鍚嶇О', + dataIndex: 'label', + width: '25%' + }, + { + title: '瀛楁', + dataIndex: 'field', + width: '25%' + }, + { + title: '鏁版嵁绫诲瀷', + dataIndex: 'datatype', + width: '25%', + }, + { + title: '鎿嶄綔', + align: 'center', + width: '25%', + dataIndex: 'operation', + render: (text, record) => + (<div> + <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <Popconfirm + title={this.props.dict['model.query.delete']} + okText={this.props.dict['model.confirm']} + cancelText={this.props.dict['model.cancel']} + onConfirm={() => this.deleteColumn(record) + }> + <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span> + </Popconfirm> + </div>) + } + ], + scriptsColumns: [ + { + title: 'SQL', + dataIndex: 'sql', + width: '60%', + render: (text) => ( + <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph> + ) + }, + { + title: '鐘舵��', + dataIndex: 'status', + width: '20%', + render: (text, record) => record.status === 'false' ? + ( + <div> + {this.props.dict['model.status.forbidden']} + <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" /> + </div> + ) : + ( + <div> + {this.props.dict['model.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, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <span className="operation-btn" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span> + <span className="operation-btn" title={this.props.dict['model.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span> + <Popconfirm + title={this.props.dict['model.query.delete']} + okText={this.props.dict['model.confirm']} + cancelText={this.props.dict['model.cancel']} + onConfirm={() => this.deleteScript(record) + }> + <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span> + </Popconfirm> + </div>) + } + ] + } + + UNSAFE_componentWillMount() { + const { config } = this.props + + this.setState({ + columns: fromJS(config.columns).toJS(), + setting: fromJS(config.setting).toJS(), + scripts: fromJS(config.scripts).toJS() + }) + + 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) + + _sParam.open_key = Utils.encrypt(_sParam.secretkey, _sParam.timestamp, true) // 浜戠鏁版嵁楠岃瘉 + + Api.getSystemConfig(_sParam).then(res => { + if (res.status) { + let _scripts = [] + + res.data.forEach(item => { + let _item = { + name: item.funcname, + value: Utils.formatOptions(item.longparam, true) + } + + _scripts.push(_item) + }) + + this.setState({ + systemScripts: [...this.state.systemScripts, ..._scripts] + }) + } else { + notification.warning({ + top: 92, + message: res.message, + duration: 5 + }) + } + }) + } + + columnChange = (values) => { + let columns = fromJS(this.state.columns).toJS() + + if (values.uuid) { + columns = columns.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + values.uuid = Utils.getuuid() + columns.push(values) + } + + this.setState({ columns }) + } + + deleteColumn = (record) => { + this.setState({ columns: this.state.columns.filter(item => item.uuid !== record.uuid) }) + } + + deleteScript = (record) => { + this.setState({ scripts: this.state.scripts.filter(item => item.uuid !== record.uuid) }) + } + + handleEdit = (record, type) => { + if (type === 'scripts') { + this.scriptsForm.edit(record) + } else if (type === 'columns') { + this.contrastForm.edit(record) + } + + let node = document.getElementById('model-verify-card-box-tab').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) + } + } + + handleStatus = (record) => { + let scripts = fromJS(this.state.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({ scripts }) + } + + handleUpDown = (record, direction) => { + let scripts = fromJS(this.state.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({ scripts }) + } + + scriptsChange = (values) => { + let scripts = fromJS(this.state.scripts).toJS() + + if (values.uuid) { + scripts = scripts.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + scripts.push(values) + } + + return new Promise((resolve, reject) => { + this.sqlverify(resolve, reject, false, scripts) + }) + } + + scriptSubmit = (values) => { + let scripts = fromJS(this.state.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({ scripts }) + } + + changeTab = (val) => { + const { activeKey } = this.state + + this.setState({loading: true}) + if (activeKey === 'setting') { + this.settingForm.handleConfirm().then(res => { + this.setState({ + setting: res + }, () => { + this.sqlverify(() => { // 楠岃瘉鎴愬姛 + this.setState({ + activeKey: val, + loading: false + }) + }, () => { // 楠岃瘉澶辫触 + this.setState({ + loading: false + }) + }, true) + }) + }, () => { + this.setState({loading: false}) + }) + } else if (activeKey === 'columns') { + this.setState({ + activeKey: val, + loading: false + }) + // this.sqlverify(() => { // 楠岃瘉鎴愬姛 + // this.setState({ + // activeKey: val, + // loading: false + // }) + // }, () => { // 楠岃瘉澶辫触 + // this.setState({ + // loading: false + // }) + // }, true) + } else if (activeKey === 'scripts') { + let _loading = false + if (this.scriptsForm && this.scriptsForm.state.editItem) { + _loading = true + } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) { + _loading = true + } + + if (_loading) { + notification.warning({ + top: 92, + message: '瀛樺湪鏈繚瀛樿剼鏈紝璇风偣鍑荤‘瀹氫繚瀛橈紝鎴栫偣鍑诲彇娑堟斁寮冧慨鏀癸紒', + duration: 5 + }) + this.setState({ + loading: false + }) + return + } + + this.setState({ + activeKey: val, + loading: false + }) + + // this.sqlverify(() => { // 楠岃瘉鎴愬姛 + // this.setState({ + // activeKey: val, + // loading: false + // }) + // }, () => { // 楠岃瘉澶辫触 + // this.setState({ + // loading: false + // }) + // }, true) + } + } + + submitDataSource = () => { + const { activeKey, setting, columns, scripts } = this.state + + return new Promise((resolve, reject) => { + if (activeKey === 'setting') { + this.settingForm.handleConfirm().then(res => { + this.setState({ + setting: res + }, () => { + this.sqlverify(() => { resolve({setting: res, columns, scripts }) }, reject, false) + }) + }, () => { + reject() + }) + } else if (activeKey === 'columns') { + this.sqlverify(() => { resolve({setting, columns, scripts }) }, reject, false) + } else if (activeKey === 'scripts') { + let _loading = false + if (this.scriptsForm && this.scriptsForm.state.editItem) { + _loading = true + } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) { + _loading = true + } + + if (_loading) { + notification.warning({ + top: 92, + message: '瀛樺湪鏈繚瀛樿剼鏈紝璇风偣鍑荤‘瀹氫繚瀛橈紝鎴栫偣鍑诲彇娑堟斁寮冧慨鏀癸紒', + duration: 5 + }) + reject() + return + } + + this.sqlverify(() => { resolve({setting, columns, scripts }) }, reject, false) + } + }) + } + + sqlverify = (resolve, reject, change = false, testScripts) => { + const { searches } = this.props + const { columns, setting, scripts } = this.state + + let _scripts = scripts.filter(item => item.status !== 'false') + + if (testScripts) { + _scripts = testScripts.filter(item => item.status !== 'false') + } + if (!change && setting.interType === 'inner' && !setting.innerFunc && setting.execute === 'false' && _scripts.length === 0) { + notification.warning({ + top: 92, + message: '涓嶆墽琛岄粯璁ql鏃讹紝璇锋坊鍔犺嚜瀹氫箟鑴氭湰锛�', + duration: 5 + }) + reject() + return + } + + if ((setting.interType === 'inner' && !setting.innerFunc && setting.execute !== 'false') || _scripts.length > 0) { + let param = { + func: 's_debug_sql', + LText: SettingUtils.getDebugSql(setting, _scripts, columns, searches) + } + 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() + } else { + reject() + Modal.error({ + title: result.message + }) + } + }) + } else { + resolve() + } + } + + updatefields = (columns) => { + this.setState({ + columns: columns + }) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊 + */ + componentWillUnmount () { + this.setState = () => { + return + } + } + + render() { + const { columns, setting, scripts, colColumns, scriptsColumns, activeKey, loading } = this.state + + return ( + <div id="model-verify-card-box-tab"> + {loading && <Spin size="large" />} + <Tabs activeKey={activeKey} className="verify-card-box" onChange={this.changeTab}> + <TabPane tab="鏁版嵁婧�" key="setting"> + <SettingForm + menuId={this.props.menuId} + dict={this.props.dict} + permFuncField={this.props.permFuncField} + columns={columns} + setting={setting} + scripts={scripts} + wrappedComponentRef={(inst) => this.settingForm = inst} + /> + </TabPane> + <TabPane tab="瀛楁闆�" key="columns"> + <ColForm + dict={this.props.dict} + columnChange={this.columnChange} + wrappedComponentRef={(inst) => this.contrastForm = inst} + /> + <FieldsComponent + config={{...this.props.config, columns}} + type="fields" + tableFields={this.props.tableFields} + updatefield={this.updatefields} + /> + <Table + bordered + rowKey="uuid" + className="custom-table" + dataSource={columns} + columns={colColumns} + pagination={false} + /> + </TabPane> + <TabPane tab="鑷畾涔夎剼鏈�" key="scripts"> + <CustomScriptsForm + setting={setting} + searches={this.props.searches} + initsql={this.state.initsql} + dict={this.props.dict} + customScripts={scripts} + systemScripts={this.state.systemScripts} + scriptsChange={this.scriptsChange} + scriptSubmit={this.scriptSubmit} + wrappedComponentRef={(inst) => this.scriptsForm = inst} + /> + <Table + bordered + rowKey="uuid" + className="custom-table" + dataSource={scripts} + columns={scriptsColumns} + pagination={false} + /> + </TabPane> + </Tabs> + </div> + ) + } +} + +export default Form.create()(VerifyCard) \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/index.scss b/src/menu/datasourcecomponent/verifycard/index.scss new file mode 100644 index 0000000..31e4d0a --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/index.scss @@ -0,0 +1,81 @@ +#model-verify-card-box-tab { + .ant-spin { + position: absolute; + left: calc(50% - 16px); + top: 220px; + z-index: 1; + } + .verify-card-box { + .ant-tabs-nav-scroll { + text-align: center; + } + .ant-tabs-content { + min-height: 40vh; + } + table tr td { + word-wrap: break-word; + word-break: break-word; + } + .quickly-add { + position: relative; + width: 100px; + float: right; + top: -5px; + z-index: 2; + } + .verify-form { + .ant-input-number { + width: 100%; + } + .sql { + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + padding-top: 4px; + } + } + .sqlfield { + .ant-form-item { + margin-bottom: 5px; + } + .ant-form-item-control { + line-height: 24px; + } + .ant-form-item-label { + line-height: 25px; + } + .ant-form-item-children { + line-height: 22px; + } + .ant-col-sm-8 { + width: 10.5%; + } + .ant-col-sm-16 { + width: 89.5%; + } + } + .add { + padding-top: 4px; + } + .anticon-question-circle { + color: #c49f47; + margin-right: 3px; + } + } + .custom-table .ant-empty { + margin: 20px 8px!important; + } + .errorval { + display: inline-block; + width: 30px; + } + .operation-btn { + display: inline-block; + font-size: 16px; + padding: 0 5px; + cursor: pointer; + } + } +} \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/settingform/index.jsx b/src/menu/datasourcecomponent/verifycard/settingform/index.jsx new file mode 100644 index 0000000..2cbec37 --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/settingform/index.jsx @@ -0,0 +1,352 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, InputNumber, Select } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import { formRule } from '@/utils/option.js' +import Utils from '@/utils/utils.js' +import CodeMirror from '@/templates/zshare/codemirror' +import './index.scss' + +class SettingForm extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + menuId: PropTypes.string, // 鑿滃崟Id + permFuncField: PropTypes.any, // 鑿滃崟Id + setting: PropTypes.object, // 鏁版嵁婧愰厤缃� + columns: PropTypes.array, // 鍒楄缃� + scripts: PropTypes.array, // 鑷畾涔夎剼鏈� + } + + state = { + interType: this.props.setting.interType || 'inner', + } + + handleConfirm = () => { + const { setting } = this.props + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + // 鏁版嵁婧愬墠绔獙璇� + if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && !values.dataresource) { + notification.warning({ + top: 92, + message: '璇峰~鍐欏唴閮ㄥ嚱鏁版垨鏁版嵁婧愶紒', + duration: 5 + }) + reject() + return + } else if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && values.dataresource) { + let _quot = values.dataresource.match(/'{1}/g) + let _lparen = values.dataresource.match(/\({1}/g) + let _rparen = values.dataresource.match(/\){1}/g) + + _quot = _quot ? _quot.length : 0 + _lparen = _lparen ? _lparen.length : 0 + _rparen = _rparen ? _rparen.length : 0 + + if (_quot % 2 !== 0) { + notification.warning({ + top: 92, + message: '鏁版嵁婧愪腑\'蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + reject() + return + } else if (_lparen !== _rparen) { + notification.warning({ + top: 92, + message: '鏁版嵁婧愪腑()蹇呴』鎴愬鍑虹幇', + duration: 5 + }) + reject() + return + } else if (/--/ig.test(values.dataresource)) { + notification.warning({ + top: 92, + message: '鏁版嵁婧愪腑锛屼笉鍙嚭鐜板瓧绗� -- 锛屾敞閲婅鐢� /*鍐呭*/', + duration: 5 + }) + reject() + return + } + + 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.execute !== 'false' && + /[^\s]+\s+[^\s]+/ig.test(values.dataresource) && setting.dataresource !== values.dataresource + ) { + let param = { + func: 's_DataSrc_Save', + LText: values.dataresource, + MenuID: this.props.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) + } + + resolve(values) + } else { + reject(err) + } + }) + }) + } + + onRadioChange = (e, key) => { + let value = e.target.value + + if (key === 'interType') { + this.setState({ + interType: value + }) + } + } + + render() { + const { setting, permFuncField, columns } = this.props + const { getFieldDecorator } = this.props.form + const { interType } = this.state + + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + let tooltip = null + let rules = [] + + if (permFuncField && permFuncField.length > 0) { + tooltip = '寮�澶村彲鐢ㄥ瓧绗︼細' + permFuncField.join(', ') + let str = '^(' + permFuncField.join('|') + ')' + let _patten = new RegExp(str + formRule.func.innerPattern + '$', 'g') + + rules.push({ + pattern: _patten, + message: formRule.func.innerMessage + }) + } + + return ( + <div className="model-datasource-setting-form-box"> + <Form {...formItemLayout} className="model-setting-form"> + <Row gutter={24}> + <Col span={8}> + <Form.Item label="鏍囬"> + {getFieldDecorator('title', { + initialValue: setting.title + })(<Input placeholder={''} autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={ + <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�"> + <Icon type="question-circle" /> + 缁勪欢鍚嶇О + </Tooltip> + }> + {getFieldDecorator('name', { + initialValue: setting.name, + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!' + } + ] + })(<Input placeholder={''} autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label={ + <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒�24浠姐��"> + <Icon type="question-circle" /> + 瀹藉害 + </Tooltip> + }> + {getFieldDecorator('span', { + initialValue: setting.span || 12, + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '瀹藉害!' + } + ] + })(<InputNumber min={1} max={24} precision={0} />)} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label="琛ㄥ悕"> + {getFieldDecorator('tableName', { + initialValue: setting.tableName, + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '琛ㄥ悕!' + }, + ] + })(<Input placeholder={''} autoComplete="off" />)} + </Form.Item> + </Col> + <Col span={8}> + <Form.Item label="鎺ュ彛绫诲瀷"> + {getFieldDecorator('interType', { + initialValue: interType, + rules: [ + { + required: true, + message: this.props.dict['form.required.select'] + '鎺ュ彛绫诲瀷!' + }, + ] + })( + <Radio.Group onChange={(e) => {this.onRadioChange(e, 'interType')}}> + <Radio value="inner">鍐呴儴</Radio> + <Radio value="outer">澶栭儴</Radio> + </Radio.Group>)} + </Form.Item> + </Col> + {interType === 'inner' ? <Col span={8}> + <Form.Item label={tooltip ? + <Tooltip placement="topLeft" title={tooltip}> + <Icon type="question-circle" /> + 鍐呴儴鍑芥暟 + </Tooltip> : '鍐呴儴鍑芥暟' + }> + {getFieldDecorator('innerFunc', { + initialValue: setting.innerFunc || '', + rules: rules + })(<Input placeholder={''} autoComplete="off" />)} + </Form.Item> + </Col> : null} + {interType === 'outer' ? <Col span={8}> + <Form.Item label="鎺ュ彛鍦板潃"> + {getFieldDecorator('interface', { + initialValue: setting.interface || '', + rules: [ + { + required: true, + message: this.props.dict['form.required.input'] + '鎺ュ彛鍦板潃!' + }, + ] + })(<Input placeholder={''} autoComplete="off" />)} + </Form.Item> + </Col> : null} + {interType === 'outer' ? <Col span={8}> + <Form.Item label="澶栭儴鍑芥暟"> + {getFieldDecorator('outerFunc', { + initialValue: setting.outerFunc || '', + rules: [ + + ] + })(<Input placeholder={''} autoComplete="off" />)} + </Form.Item> + </Col> : null} + {interType === 'inner' ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}> + <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 2 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 22 }} } label={ + <Tooltip placement="topLeft" title={'浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\''}> + <Icon type="question-circle" /> + 鏁版嵁婧� + </Tooltip> + }> + {getFieldDecorator('dataresource', { + initialValue: setting.dataresource || '' + })(<CodeMirror />)} + </Form.Item> + </Col> : null} + <Col span={8}> + <Form.Item label={ + <Tooltip placement="topLeft" title="楂樺害涓虹┖鏃讹紝浣跨敤绯荤粺鑷�傚簲璁剧疆銆�"> + <Icon type="question-circle" /> + 楂樺害 + </Tooltip> + }> + {getFieldDecorator('height', { + initialValue: setting.height || 400 + })(<InputNumber min={100} max={1500} precision={0} />)} + </Form.Item> + </Col> + {interType === 'inner' ? <Col span={8}> + <Form.Item label={ + <Tooltip placement="topLeft" title={'鏌ヨ鏃讹紝鎼滅储鏉′欢浠here鏉′欢鎷兼帴杩涘叆sql锛岀粺璁℃椂锛屽皢鏁版嵁婧愪腑浠モ�淍+鎼滅储瀛楁+@鈥濈殑鍐呭锛屼互鎼滅储鏉′欢涓殑鍊艰繘琛屾浛鎹㈠悗锛屾彁浜ゆ煡璇紝娉細鏌ヨ绫诲瀷浠呭湪浣跨敤绯荤粺鍑芥暟鏃舵湁鏁堛��'}> + <Icon type="question-circle" /> + 鏌ヨ绫诲瀷 + </Tooltip> + }> + {getFieldDecorator('queryType', { + initialValue: setting.queryType || 'query' + })( + <Radio.Group> + <Radio value="query">鏌ヨ</Radio> + <Radio value="statistics">缁熻</Radio> + </Radio.Group>)} + </Form.Item> + </Col> : null} + <Col span={8}> + <Form.Item label="涓婚敭"> + {getFieldDecorator('primaryKey', { + initialValue: setting.primaryKey || '' + })( + <Select> + {columns.map((option, i) => + <Select.Option key={i} value={option.field}> + {option.label} + </Select.Option> + )} + </Select> + )} + </Form.Item> + </Col> + {interType === 'inner' ? <Col span={8}> + <Form.Item label="榛樿sql"> + {getFieldDecorator('execute', { + initialValue: setting.execute || 'true' + })( + <Radio.Group> + <Radio value="true">鎵ц</Radio> + <Radio value="false">涓嶆墽琛�</Radio> + </Radio.Group>)} + </Form.Item> + </Col> : null} + <Col span={8}> + <Form.Item label="鍒濆鍖栨暟鎹�"> + {getFieldDecorator('onload', { + initialValue: setting.onload || 'true' + })( + <Radio.Group> + <Radio value="true">鍔犺浇</Radio> + <Radio value="false">涓嶅姞杞�</Radio> + </Radio.Group>)} + </Form.Item> + </Col> + </Row> + </Form> + </div> + ) + } +} + +export default Form.create()(SettingForm) \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/settingform/index.scss b/src/menu/datasourcecomponent/verifycard/settingform/index.scss new file mode 100644 index 0000000..d24bedd --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/settingform/index.scss @@ -0,0 +1,24 @@ +.model-datasource-setting-form-box { + position: relative; + + .model-setting-form { + .data-source { + .ant-form-item-label { + width: 11%; + } + .ant-form-item-control-wrapper { + width: 89%; + } + .CodeMirror { + height: 150px; + } + } + .anticon-question-circle { + color: #c49f47; + margin-right: 3px; + } + } + .ant-input-number { + width: 100%; + } +} \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/settingform/utils.jsx b/src/menu/datasourcecomponent/verifycard/settingform/utils.jsx new file mode 100644 index 0000000..ebd508d --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/settingform/utils.jsx @@ -0,0 +1,84 @@ + +export default class SettingUtils { + /** + * @description 鐢熸垚椤甸潰鏌ヨ璇彞 + * @return {String} arr_field 鏄剧ず鍒楀瓧娈� + * @return {String} search 鎼滅储鏉′欢 + * @return {Object} setting 椤甸潰璁剧疆 + * @return {Array} regoptions 鎼滅储鏉′欢姝e垯鏇挎崲 + */ + static getDebugSql (setting, arr_field, regoptions, search) { + let sql = '' + let _dataresource = setting.dataresource + let _customScript = setting.customScript + + if (setting.interType === 'inner' && !setting.innerFunc && setting.default === 'false') { + _dataresource = '' + } + + if (_dataresource) { + _dataresource = _dataresource.replace(/@\$|\$@/ig, '') + } + if (_customScript) { + _customScript = _customScript.replace(/@\$|\$@/ig, '') + } + + // 姝e垯鏇挎崲 + let _regoptions = regoptions.map(item => { + return { + reg: new RegExp('@' + item.key + '@', 'ig'), + value: `'${item.value}'` + } + }) + let _search = search + + if (setting.queryType === 'statistics' && _dataresource) { + _regoptions.forEach(item => { + _dataresource = _dataresource.replace(item.reg, item.value) + }) + + _search = '' + } + + if (_customScript) { + _regoptions.push({ + reg: new RegExp('@orderBy@', 'ig'), + value: setting.order + }) + if (setting.laypage !== 'false') { + _regoptions.push({ + reg: new RegExp('@pageSize@', 'ig'), + value: 10 + }, { + reg: new RegExp('@pageIndex@', 'ig'), + value: 1 + }) + } + _regoptions.forEach(item => { + _customScript = _customScript.replace(item.reg, item.value) + }) + } + + // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 + if (arr_field && _dataresource) { + if (/\s/.test(_dataresource)) { + _dataresource = '(' + _dataresource + ') tb' + } + + _dataresource = `select ${setting.laypage !== 'false' ? 'top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ? 'where rows > 0' : ''} order by tmptable.rows` + } + + if (_customScript) { + sql = `${_customScript} + ${_dataresource} + aaa: + if @ErrorCode!='' + insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@ + ` + } else { + sql = _dataresource + } + + return sql + } +} \ No newline at end of file diff --git a/src/menu/datasourcecomponent/verifycard/utils.jsx b/src/menu/datasourcecomponent/verifycard/utils.jsx new file mode 100644 index 0000000..8d04983 --- /dev/null +++ b/src/menu/datasourcecomponent/verifycard/utils.jsx @@ -0,0 +1,111 @@ + +export default class SettingUtils { + /** + * @description 鐢熸垚椤甸潰鏌ヨ璇彞 + * @return {String} scripts 鑷畾涔夎剼鏈� + * @return {String} searches 鎼滅储鏉′欢 + * @return {Object} setting 椤甸潰璁剧疆 + * @return {Array} columns 鏄剧ず瀛楁 + */ + static getDebugSql (setting, scripts, columns, searches) { + let sql = '' + let _dataresource = '' + let _customScript = '' + let arr_field = columns.map(item => item.field).join(',') + + if (scripts.length > 0) { + scripts.forEach(item => { + _customScript += ` + ${item.sql} + ` + }) + } + + if (_customScript) { + _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg ='' + ${_customScript} + ` + } + + if (setting.interType === 'inner' && !setting.innerFunc && setting.execute !== 'false') { + _dataresource = setting.dataresource + } + + if (_dataresource) { + _dataresource = _dataresource.replace(/@\$|\$@/ig, '') + } + if (_customScript) { + _customScript = _customScript.replace(/@\$|\$@/ig, '') + } + + // 姝e垯鏇挎崲 + let _regoptions = searches.map(item => { + return { + reg: new RegExp('@' + item.key + '@', 'ig'), + value: `'${item.value}'` + } + }) + let _search = '' + + // 鏃ュ巻涓殑骞翠唤鏇挎崲 + if (setting.queryType === 'statistics' || _customScript) { + _regoptions.push({ + reg: new RegExp('@calendarDate@', 'ig'), + value: `1970-01-01 00:00:00.000` + }) + _regoptions.push({ + reg: new RegExp('@calendarDate1@', 'ig'), + value: `2030-12-31 23:59:59.999` + }) + } + + if (setting.queryType === 'statistics' && _dataresource) { + _regoptions.forEach(item => { + _dataresource = _dataresource.replace(item.reg, item.value) + }) + + _search = '' + } + + if (_customScript) { + _regoptions.push({ + reg: new RegExp('@orderBy@', 'ig'), + value: setting.order + }) + if (setting.laypage !== 'false') { + _regoptions.push({ + reg: new RegExp('@pageSize@', 'ig'), + value: 10 + }, { + reg: new RegExp('@pageIndex@', 'ig'), + value: 1 + }) + } + _regoptions.forEach(item => { + _customScript = _customScript.replace(item.reg, item.value) + }) + } + + // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 + if (arr_field && _dataresource) { + if (/\s/.test(_dataresource)) { + _dataresource = '(' + _dataresource + ') tb' + } + + _dataresource = `select ${setting.laypage !== 'false' ? 'top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ? 'where rows > 0' : ''} order by tmptable.rows` + } + + if (_customScript) { + sql = `${_customScript} + ${_dataresource} + aaa: + if @ErrorCode!='' + insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@ + ` + } else { + sql = _dataresource + } + + return sql + } +} \ No newline at end of file diff --git a/src/menu/menuform/index.jsx b/src/menu/menuform/index.jsx index 9f714ff..16bbb7e 100644 --- a/src/menu/menuform/index.jsx +++ b/src/menu/menuform/index.jsx @@ -1,5 +1,6 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' +import { fromJS } from 'immutable' import { Form, Row, Col, Input, Select, notification } from 'antd' import Api from '@/api' @@ -14,6 +15,7 @@ MenuName: PropTypes.string, MenuNo: PropTypes.string, parentId: PropTypes.string, + initMenuList: PropTypes.func, updateConfig: PropTypes.func } @@ -56,6 +58,8 @@ } }) + this.props.initMenuList(fromJS(menulist).toJS()) + this.setState({ fstMenuId: result.FstIDSeleted, menulist, diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx index cc2146d..ac08014 100644 --- a/src/menu/menushell/card.jsx +++ b/src/menu/menushell/card.jsx @@ -7,7 +7,7 @@ const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar')) -const Card = ({ id, card, moveCard, findCard, editId, editCard, delCard, hasDrop, doubleClickCard, updateConfig }) => { +const Card = ({ id, config, card, moveCard, findCard, editId, editCard, delCard, hasDrop, doubleClickCard, updateConfig }) => { const originalIndex = findCard(id).index const [{ isDragging }, drag] = useDrag({ item: { type: 'menu', id, originalIndex }, @@ -39,12 +39,12 @@ const getCardComponent = () => { if (card.type === 'bar') { - return (<AntvBar card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />) + return (<AntvBar config={config} card={card} triggerEdit={editCard} editId={editId} updateConfig={updateConfig} />) } } return ( - <div className="mk-component-card" ref={node => drag(drop(node))} style={style}> + <div className={'ant-col mk-component-card ant-col-' + (card.setting ? card.setting.span : 12)} ref={node => drag(drop(node))} style={style}> {getCardComponent()} <Icon className="remove-component" title="delete" type="delete" onClick={() => delCard(id)} /> </div> diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx index baa9e5e..c2827ec 100644 --- a/src/menu/menushell/index.jsx +++ b/src/menu/menushell/index.jsx @@ -70,11 +70,12 @@ }) return ( - <div ref={drop} className="menu-shell-inner"> + <div ref={drop} className="ant-row menu-shell-inner"> {cards.map(card => ( <Card id={card.uuid} key={card.uuid} + config={config} card={card} editId={editId} moveCard={moveCard} diff --git a/src/menu/menushell/index.scss b/src/menu/menushell/index.scss index 26d5c35..fd9cc3f 100644 --- a/src/menu/menushell/index.scss +++ b/src/menu/menushell/index.scss @@ -1,25 +1,42 @@ .menu-shell-inner { min-height: calc(100vh - 150px); + margin: -8px; + + >.ant-col { + padding: 8px; + } + .mk-component-card { position: relative; .remove-component { position: absolute; - right: 2px; - top: 50%; - background: #ff4d4f; + right: 40px; + top: -13px; + color: #ff4d4f; border-radius: 2px; - padding: 4px; - color: #ffffff; + padding: 5px; cursor: pointer; - display: none; + opacity: 0; } } .mk-component-card:hover { .remove-component { - display: inline-block; + opacity: 1; + } + .model-datasource > .anticon-setting { + opacity: 1; } } >.ant-empty { padding-top: 150px; } + + .model-datasource > .anticon-setting { + font-size: 16px; + padding: 5px; + position: absolute; + right: 0px; + top: -19px; + opacity: 0; + } } \ No newline at end of file diff --git a/src/menu/searchcomponent/dategroup/index.jsx b/src/menu/searchcomponent/dategroup/index.jsx new file mode 100644 index 0000000..37b8769 --- /dev/null +++ b/src/menu/searchcomponent/dategroup/index.jsx @@ -0,0 +1,32 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Tag } from 'antd' +import './index.scss' + +const { CheckableTag } = Tag + +class DateGroup extends Component { + static propTpyes = { + card: PropTypes.object // 瀛楀吀椤� + } + + render() { + const { card } = this.props + let tabs = {day: '鏃�', week: '鍛�', month: '鏈�', quarter: '瀛�', year: '骞�', customized: '鑷畾涔�'} + + return ( + <div className="model-date-group"> + {card.items.map(tab => ( + <CheckableTag + key={tab} + checked={card.initval && card.initval.includes(tab)} + > + {tabs[tab]} + </CheckableTag> + ))} + </div> + ) + } +} + +export default DateGroup \ No newline at end of file diff --git a/src/menu/searchcomponent/dategroup/index.scss b/src/menu/searchcomponent/dategroup/index.scss new file mode 100644 index 0000000..6782732 --- /dev/null +++ b/src/menu/searchcomponent/dategroup/index.scss @@ -0,0 +1,38 @@ +.model-date-group { + white-space: nowrap; + line-height: 40px; + position: relative; + z-index: 1; + + .ant-tag-checkable { + border-color: #d1d5d9; + border-radius: 2px; + margin-right: 2px; + padding: 2px 6px; + } + .ant-tag-checkable-checked { + border-color: #1890ff; + } +} + +@media screen and (min-width: 1440px) { + .model-date-group { + .ant-tag-checkable { + padding: 2px 7px; + } + } +} +@media screen and (min-width: 1600px) { + .model-date-group { + .ant-tag-checkable { + padding: 2px 9px; + } + } +} +@media screen and (min-width: 1920px) { + .model-date-group { + .ant-tag-checkable { + padding: 2px 11px; + } + } +} \ No newline at end of file diff --git a/src/menu/searchcomponent/dragsearch/card.jsx b/src/menu/searchcomponent/dragsearch/card.jsx new file mode 100644 index 0000000..b8d4a54 --- /dev/null +++ b/src/menu/searchcomponent/dragsearch/card.jsx @@ -0,0 +1,98 @@ +import React from 'react' +import { useDrag, useDrop } from 'react-dnd' +import { Icon, Select, DatePicker, Input } from 'antd' +import moment from 'moment' + +import DateGroup from '../dategroup' +import './index.scss' + +const { MonthPicker, WeekPicker, RangePicker } = DatePicker + +const Card = ({ id, card, moveCard, findCard, editCard, delCard }) => { + const originalIndex = findCard(id).index + const [{ isDragging }, drag] = useDrag({ + item: { type: 'search', id, originalIndex }, + collect: monitor => ({ + isDragging: monitor.isDragging(), + }), + }) + const [, drop] = useDrop({ + accept: 'search', + canDrop: () => true, + drop: (item) => { + if (!item.hasOwnProperty('originalIndex')) { + + } + }, + hover({ id: draggedId }) { + if (!draggedId) return + if (draggedId !== id) { + const { index: overIndex } = findCard(id) + moveCard(draggedId, overIndex) + } + }, + }) + const opacity = isDragging ? 0 : 1 + + let _defaultValue = '' // 涓嬫媺鎼滅储銆佹椂闂磋寖鍥寸被鍨嬶紝鍒濆鍊奸渶瑕侀澶勭悊 + + if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') { + if (card.initval) { + let _option = card.options.filter(option => option.Value === card.initval)[0] + if (_option) { + _defaultValue = _option.Text || '' + } else { + _defaultValue = '' + } + } else if (card.setAll === 'true') { + _defaultValue = 'All' + } + } else if (card.type === 'daterange') { + _defaultValue = [null, null] + if (card.initval) { + try { + let _initval = JSON.parse(card.initval) + _defaultValue = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')] + } catch { + _defaultValue = [null, null] + } + } + } + + return ( + <div className="page-card" style={{ opacity: opacity}}> + <div ref={node => drag(drop(node))}> + <div className="ant-form-item"> + {card.type === 'text' ? + <Input placeholder={card.label} style={{marginTop: '4px'}} value={card.initval} /> : null + } + {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ? + <Select placeholder={card.label} value={_defaultValue}></Select> : null + } + {card.type === 'date' ? + <DatePicker placeholder={card.label} value={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null + } + {card.type === 'dateweek' ? + <WeekPicker placeholder={card.label} value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null + } + {card.type === 'datemonth' ? + <MonthPicker placeholder={card.label} value={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null + } + {card.type === 'daterange' ? + <RangePicker + className="data-range" + placeholder={['BeginTime', 'EndTime']} + renderExtraFooter={() => 'extra footer'} + value={_defaultValue} + /> : null + } + {card.type === 'group' ? <DateGroup card={card} /> : null } + <div className="input-mask"></div> + </div> + </div> + <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} /> + <Icon className="edit close" title="delete" type="close" onClick={() => delCard(id)} /> + </div> + ) +} +export default Card diff --git a/src/menu/searchcomponent/dragsearch/index.jsx b/src/menu/searchcomponent/dragsearch/index.jsx new file mode 100644 index 0000000..c7f08e5 --- /dev/null +++ b/src/menu/searchcomponent/dragsearch/index.jsx @@ -0,0 +1,96 @@ +import React, { useState } from 'react' +import { useDrop } from 'react-dnd' +import { is, fromJS } from 'immutable' +import update from 'immutability-helper' +import { Col, Icon } from 'antd' +import Utils from '@/utils/utils.js' +import Card from './card' +import './index.scss' + +const Container = ({list, handleList, handleMenu, deleteMenu }) => { + const [cards, setCards] = useState(list) + const moveCard = (id, atIndex) => { + const { card, index } = findCard(id) + const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] }) + handleList(_cards) + } + + if (!is(fromJS(cards), fromJS(list))) { + setCards(list) + } + + const findCard = id => { + const card = cards.filter(c => `${c.uuid}` === id)[0] + return { + card, + index: cards.indexOf(card), + } + } + + const editCard = id => { + const { card } = findCard(id) + handleMenu(card) + } + + const delCard = id => { + const { card } = findCard(id) + deleteMenu(card) + } + + const [, drop] = useDrop({ + accept: 'search', + drop(item) { + if (item.hasOwnProperty('originalIndex')) { + return + } + } + }) + + const addsearch = (e) => { + e.stopPropagation() + + let newcard = {} + newcard.uuid = Utils.getuuid() + newcard.focus = true + + newcard.label = 'label' + newcard.initval = '' + newcard.type = 'select' + newcard.resourceType = '0' + newcard.options = [] + newcard.setAll = 'false' + newcard.orderType = 'asc' + newcard.display = 'dropdown' + newcard.match = '=' + + let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0 + + const { index: overIndex } = findCard(`${targetId}`) + let targetIndex = overIndex + + targetIndex++ + + const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] }) + + handleList(_cards, newcard) + } + + return ( + <div ref={drop} className="ant-row"> + {cards.map(card => ( + <Col key={card.uuid} span={card.ratio || 6}> + <Card + id={`${card.uuid}`} + card={card} + moveCard={moveCard} + editCard={editCard} + delCard={delCard} + findCard={findCard} + /> + </Col> + ))} + <Icon type="plus" onClick={addsearch}/> + </div> + ) +} +export default Container diff --git a/src/menu/searchcomponent/dragsearch/index.scss b/src/menu/searchcomponent/dragsearch/index.scss new file mode 100644 index 0000000..369ae98 --- /dev/null +++ b/src/menu/searchcomponent/dragsearch/index.scss @@ -0,0 +1,6 @@ +.common-drawarea-placeholder { + width: 100%; + line-height: 65px; + text-align: center; + color: #bcbcbc; +} \ No newline at end of file diff --git a/src/menu/searchcomponent/index.jsx b/src/menu/searchcomponent/index.jsx new file mode 100644 index 0000000..e8e7ab4 --- /dev/null +++ b/src/menu/searchcomponent/index.jsx @@ -0,0 +1,311 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { Modal, notification } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import Utils from '@/utils/utils.js' +import zhCN from '@/locales/zh-CN/model.js' +import enUS from '@/locales/en-US/model.js' +import { getSearchForm } from '@/templates/zshare/formconfig' + +import SearchForm from './searchform' +import DragElement from './dragsearch' +import './index.scss' + +const { confirm } = Modal + +class SearchComponent extends Component { + static propTpyes = { + config: PropTypes.object, // 閰嶇疆淇℃伅 + sysRoles: PropTypes.array, // 瑙掕壊鍒楄〃锛岄粦鍚嶅崟 + updatesearch: PropTypes.func // 鏇存柊 + } + + state = { + dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + searchlist: null, // 鎼滅储鏉′欢闆� + sqlVerifing: false, // sql楠岃瘉涓� + visible: false, // 妯℃�佹鎺у埗 + card: null // 缂栬緫涓厓绱� + } + + /** + * @description 鎼滅储鏉′欢鍒濆鍖� + */ + UNSAFE_componentWillMount () { + this.setState({ + searchlist: fromJS(this.props.config.search).toJS() + }) + } + + /** + * @description 鐩戝惉鍒版悳绱㈡潯浠跺鍒舵椂锛岃Е鍙戞悳绱㈡潯浠剁紪杈� + */ + UNSAFE_componentWillReceiveProps (nextProps) { + const { searchlist } = this.state + + if (!is(fromJS(nextProps.config.search), fromJS(this.props.config.search)) && !is(fromJS(nextProps.config.search), fromJS(searchlist))) { + this.setState({searchlist: fromJS(nextProps.config.search).toJS()}) + } + } + + /** + * @description 鎼滅储鏉′欢椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞 + */ + handleList = (list, card) => { + const { config } = this.props + + if (card) { + this.setState({searchlist: list}) + this.handleSearch(card) + } else { + this.setState({searchlist: list}, ()=> { + this.props.updatesearch({...config, search: list}) + }) + } + } + + /** + * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭� + */ + handleSearch = (card) => { + const { searchlist } = this.state + let linkableFields = [] + + searchlist.forEach(item => { + if (item.uuid !== card.uuid && (item.type === 'select' || item.type === 'link')) { + linkableFields.push({ + value: item.field, + text: item.label + }) + } + }) + + this.setState({ + visible: true, + card: card, + formlist: getSearchForm(card, this.props.sysRoles, linkableFields) + }) + } + + /** + * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎 + */ + editModalCancel = () => { + const { card } = this.state + + if (card.focus) { + let searchlist = fromJS(this.state.searchlist).toJS() + + searchlist = searchlist.filter(item => item.uuid !== card.uuid) + + this.setState({ + card: null, + searchlist: searchlist, + visible: false + }) + } else { + this.setState({ + card: null, + visible: false + }) + } + } + + /** + * @description 鎼滅储淇敼鍚庢彁浜や繚瀛� + * 1銆佸幓闄ょ郴缁熼粯璁ゆ悳绱㈡潯浠� + * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙 + * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚� + * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉 + */ + handleSubmit = () => { + const { config } = this.props + let _searchlist = fromJS(this.state.searchlist).toJS() + + this.searchFormRef.handleConfirm().then(res => { + let fieldrepet = false // 瀛楁閲嶅 + let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅 + + _searchlist = _searchlist.filter(item => !item.origin || item.uuid === res.uuid) // 鍘婚櫎绯荤粺椤� + + _searchlist = _searchlist.map(item => { // 鏁版嵁鏇存柊鍙婇噸澶嶆娴� + if (item.uuid !== res.uuid && res.field && item.field) { + let itemFields = [] + if (item.type === 'text') { + itemFields = item.field.split(',') + } else if (item.type === 'group') { + itemFields = [item.field, item.datefield] + } else { + itemFields = [item.field] + } + + let resFields = [] + if (res.type === 'text') { + resFields = res.field.split(',') + } else if (res.type === 'group') { + resFields = [res.field, res.datefield] + } else { + resFields = [res.field] + } + + let setFields = Array.from(new Set([...itemFields, ...resFields])) + + if (setFields.length < itemFields.length + resFields.length && (res.type !== 'date' || item.type !== 'date')) { + fieldrepet = true + } else if (item.label === res.label) { + labelrepet = true + } + } + + if (item.uuid === res.uuid) { + return res + } else { + return item + } + }) + + if (fieldrepet) { + notification.warning({ + top: 92, + message: this.state.dict['model.field.exist'] + ' !', + duration: 5 + }) + return + } else if (labelrepet) { + notification.warning({ + top: 92, + message: this.state.dict['model.name.exist'] + ' !', + duration: 5 + }) + return + } + + if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) { + this.setState({ + sqlVerifing: true + }) + + let param = { + func: 's_debug_sql', + LText: res.dataSource + } + + param.LText = param.LText.replace(/@\$|\$@/ig, '') + + 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) + + if (window.GLOB.mainSystemApi && res.database === 'sso') { + param.rduri = window.GLOB.mainSystemApi + } + + Api.getLocalConfig(param).then(result => { + if (result.status) { + this.setState({ + sqlVerifing: false, + searchlist: _searchlist, + visible: false + }, ()=> { + this.props.updatesearch({...config, search: _searchlist}) + }) + } else { + this.setState({sqlVerifing: false}) + + Modal.error({ + title: result.message + }) + } + }) + } else { + this.setState({ + searchlist: _searchlist, + visible: false + }, ()=> { + this.props.updatesearch({...config, search: _searchlist}) + }) + } + }) + } + + /** + * @description 鎼滅储鏉′欢鍒犻櫎 + */ + deleteElement = (card) => { + const { config } = this.props + const { dict } = this.state + let _this = this + + confirm({ + content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋, + okText: dict['model.confirm'], + cancelText: dict['model.cancel'], + onOk() { + let _searchlist = fromJS(_this.state.searchlist).toJS() + + _searchlist = _searchlist.filter(item => item.uuid !== card.uuid) + + _this.setState({ + searchlist: _searchlist + }, () => { + _this.props.updatesearch({...config, search: _searchlist}) + }) + }, + onCancel() {} + }) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊 + */ + componentWillUnmount () { + this.setState = () => { + return + } + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.state), fromJS(nextState)) + } + + render() { + const { dict, searchlist, visible, sqlVerifing } = this.state + + return ( + <div className="model-custom-search-list"> + <DragElement + list={searchlist} + handleList={this.handleList} + handleMenu={this.handleSearch} + deleteMenu={this.deleteElement} + /> + {/* 缂栬緫鎼滅储鏉′欢 */} + <Modal + title={dict['model.searchCriteria'] + '-' + dict['model.edit']} + visible={visible} + width={850} + maskClosable={false} + onOk={this.handleSubmit} + okText={dict['model.confirm']} + cancelText={dict['model.cancel']} + confirmLoading={sqlVerifing} + onCancel={this.editModalCancel} + destroyOnClose + > + <SearchForm + dict={dict} + card={this.state.card} + formlist={this.state.formlist} + inputSubmit={this.handleSubmit} + wrappedComponentRef={(inst) => this.searchFormRef = inst} + /> + </Modal> + </div> + ) + } +} + +export default SearchComponent \ No newline at end of file diff --git a/src/menu/searchcomponent/index.scss b/src/menu/searchcomponent/index.scss new file mode 100644 index 0000000..dbed81b --- /dev/null +++ b/src/menu/searchcomponent/index.scss @@ -0,0 +1,78 @@ +.model-custom-search-list { + padding: 0px; + + .anticon-question-circle { + color: #c49f47; + position: relative; + left: -15px; + top: 5px; + } + .ant-row .ant-col { + float: right; + padding: 0 6px; + margin-top: 5px; + } + .ant-row .anticon-plus { + color: #26C281; + float: right; + padding: 5px; + margin-top: 11px; + } + .page-card { + position: relative; + background: #ffffff; + border-radius: 2px; + .ant-form-item { + cursor: move; + display: flex; + margin-bottom: 0px; + + .ant-select { + width: 100%; + margin-top: 4px; + } + .ant-calendar-picker { + margin-top: 4px; + } + .input-mask { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + opacity: 0; + z-index: 2; + } + .data-range .ant-calendar-picker-input { + padding: 4px 20px 4px 5px; + font-size: 13px; + } + } + .edit { + position: absolute; + left: 5px; + top: 5px; + color: #1890ff; + cursor: pointer; + display: none; + z-index: 3; + } + .edit.copy { + left: 20px; + color: #26C281; + } + .edit.close { + left: 30px; + color: #ff4d4f; + } + } + .page-card:hover { + .edit { + display: inline-block; + } + } + .ant-calendar-picker { + min-width: 100px!important; + width: 100%; + } +} \ No newline at end of file diff --git a/src/menu/searchcomponent/searcheditable/index.jsx b/src/menu/searchcomponent/searcheditable/index.jsx new file mode 100644 index 0000000..4a560c4 --- /dev/null +++ b/src/menu/searchcomponent/searcheditable/index.jsx @@ -0,0 +1,307 @@ +import React, {Component} from 'react' +import { is, fromJS } from 'immutable' +import { Table, Input, Popconfirm, Form, Icon } from 'antd' +import Utils from '@/utils/utils.js' +import './index.scss' + +const EditableContext = React.createContext() + +const EditableRow = ({ form, index, ...props }) => ( + <EditableContext.Provider value={form}> + <tr {...props} /> + </EditableContext.Provider> +) + +const EditableFormRow = Form.create()(EditableRow) + +class EditableCell extends Component { + state = { + editing: false + } + + toggleEdit = () => { + const editing = !this.state.editing + this.setState({ editing }, () => { + if (editing && this.input && this.input.select) { + this.input.select() + } else if (editing && this.input && this.input.focus) { + this.input.focus() + } + }) + } + + save = e => { + const { record, handleSave } = this.props + this.form.validateFields((error, values) => { + handleSave({ ...record, ...values }) + if (error && error[e.currentTarget.id]) { + return + } + this.toggleEdit() + }) + } + + renderCell = form => { + this.form = form + const { children, dataIndex, record } = this.props + const { editing } = this.state + return editing ? ( + <Form.Item style={{ margin: 0 }}> + {form.getFieldDecorator(dataIndex, { + rules: [ + { + required: true, + message: 'NOT NULL.', + }, + ], + initialValue: record[dataIndex] + })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)} + </Form.Item> + ) : ( + <div + className="editable-cell-value-wrap" + onClick={this.toggleEdit} + > + {children} + </div> + ) + } + + render() { + const { + editable, + dataIndex, + title, + record, + index, + handleSave, + children, + ...restProps + } = this.props + return ( + <td {...restProps}> + {editable ? ( + <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer> + ) : ( + children + )} + </td> + ) + } +} + +class EditTable extends Component { + constructor(props) { + super(props) + let columns = [ + { + title: 'Value', + dataIndex: 'Value', + width: props.type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: 'Text', + dataIndex: 'Text', + width: props.type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: 'Action', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + this.state.dataSource.length >= 1 ? ( + <div> + <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span> + <Popconfirm + title={props.dict['header.form.query.delete']} + okText={props.dict['model.confirm']} + cancelText={props.dict['model.cancel']} + onConfirm={() => this.handleDelete(record.key) + }> + <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> + </Popconfirm> + </div> + ) : null, + } + ] + + if (props.type === 'link') { + columns.unshift({ + title: 'ParentID', + dataIndex: 'ParentID', + width: '27%', + editable: true + }) + } + + this.state = { + columns: columns, + dataSource: props.data, + count: props.data.length, + type: props.type + } + } + + handleUpDown = (record, direction) => { + const { dataSource } = this.state + let index = 0 + + let _data = dataSource.filter((item, i) => { + if (item.key === record.key) { + index = i + } + + return item.key !== record.key + }) + if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) { + return + } + + if (direction === 'up') { + _data.splice(index - 1, 0, record) + } else { + _data.splice(index + 1, 0, record) + } + + this.setState({ + dataSource: _data + }) + } + + handleDelete = key => { + const dataSource = [...this.state.dataSource] + this.setState({ dataSource: dataSource.filter(item => item.key !== key) }) + } + + handleAdd = () => { + const { type, count, dataSource } = this.state + const newData = { + key: Utils.getuuid(), + Value: `${count}`, + Text: `${count}` + } + if (type === 'link') { + newData.ParentID = `${count}` + } + this.setState({ + dataSource: [...dataSource, newData], + count: count + 1 + }) + } + + handleSave = row => { + const newData = [...this.state.dataSource] + const index = newData.findIndex(item => row.key === item.key) + const item = newData[index] + newData.splice(index, 1, { + ...item, + ...row + }) + this.setState({ dataSource: newData }) + } + + resetColumn = (type) => { + let columns = [ + { + title: 'Value', + dataIndex: 'Value', + width: type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: 'Text', + dataIndex: 'Text', + width: type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: 'Action', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + this.state.dataSource.length >= 1 ? ( + <div> + <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> + <Popconfirm + title={this.props.dict['header.form.query.delete']} + okText={this.props.dict['model.confirm']} + cancelText={this.props.dict['model.cancel']} + onConfirm={() => this.handleDelete(record.key) + }> + <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> + </Popconfirm> + </div> + ) : null, + } + ] + + if (type === 'link') { + columns.unshift({ + title: 'ParentID', + dataIndex: 'ParentID', + width: '27%', + editable: true + }) + } + + this.setState({ + columns: columns, + type: type + }) + } + + UNSAFE_componentWillReceiveProps (nextProps) { + if (this.props.type !== nextProps.type) { + this.resetColumn(nextProps.type) + } else if (!is(fromJS(this.props.data), fromJS(nextProps.data))) { + this.setState({ + dataSource: nextProps.data, + count: nextProps.data.length + }) + } + } + + render() { + const { dataSource } = this.state + const components = { + body: { + row: EditableFormRow, + cell: EditableCell + } + } + const columns = this.state.columns.map(col => { + if (!col.editable) { + return col + } + return { + ...col, + onCell: record => ({ + record, + editable: col.editable, + dataIndex: col.dataIndex, + title: col.title, + handleSave: this.handleSave, + }) + } + }) + return ( + <div className="model-search-edit-table"> + <Icon className="add-row" type="plus" onClick={this.handleAdd} /> + <Table + components={components} + rowClassName={() => 'editable-row'} + bordered + dataSource={dataSource} + columns={columns} + pagination={false} + /> + </div> + ) + } +} + +export default EditTable \ No newline at end of file diff --git a/src/menu/searchcomponent/searcheditable/index.scss b/src/menu/searchcomponent/searcheditable/index.scss new file mode 100644 index 0000000..ae28ba2 --- /dev/null +++ b/src/menu/searchcomponent/searcheditable/index.scss @@ -0,0 +1,43 @@ +.model-search-edit-table { + .add-row { + position: absolute; + z-index: 1; + right: 20px; + top: -30px; + padding: 5px; + font-size: 18px; + color: #26C281; + } + .ant-table-thead > tr > th { + padding: 10px 16px; + } + .ant-table-tbody > tr > td { + padding: 0px 16px; + } + .editable-cell-value-wrap { + cursor: pointer; + height: 40px; + width: 100px; + display: table-cell; + vertical-align: middle; + word-wrap: break-word; + word-break: break-word; + .ant-input { + height: 30px; + padding: 0 11px; + } + } + .ant-form-item-control-wrapper { + width: 100%; + } + .ant-table-placeholder { + padding: 5px 16px; + .ant-empty-normal { + margin: 0; + } + } + .operation-btn { + margin-right: 10px; + cursor: pointer; + } +} diff --git a/src/menu/searchcomponent/searchform/index.jsx b/src/menu/searchcomponent/searchform/index.jsx new file mode 100644 index 0000000..48acf2d --- /dev/null +++ b/src/menu/searchcomponent/searchform/index.jsx @@ -0,0 +1,602 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Checkbox, Cascader } from 'antd' +import { dateOptions, matchReg, formRule } from '@/utils/option.js' +import EditTable from '../searcheditable' +import Utils from '@/utils/utils.js' +import CodeMirror from '@/templates/zshare/codemirror' +import './index.scss' + +const groupOptions = [ + { + value: 'day', + label: '鏃�', + children: [ + {value: '0', label: '褰撳ぉ'}, + {value: 1, label: '鏄ㄥぉ'}, + {value: 2, label: '鍓嶅ぉ'}, + {value: 3, label: '鍓嶄笁澶�'}, + {value: 7, label: '鍓嶄竷澶�'}, + {value: 30, label: '鍓�30澶�'}, + {value: -1, label: '鏄庡ぉ'}, + {value: -2, label: '鍚庡ぉ'} + ] + }, + { + value: 'week', + label: '鍛�', + children: [ + {value: '0', label: '鏈懆'}, + {value: 1, label: '涓婂懆'}, + {value: 3, label: '鍓嶄笁鍛�'}, + {value: 7, label: '鍓嶄竷鍛�'}, + {value: -1, label: '涓嬪懆'} + ] + }, + { + value: 'month', + label: '鏈�', + children: [ + {value: '0', label: '鏈湀'}, + {value: 1, label: '涓婃湀'}, + {value: 3, label: '鍓嶄笁鏈�'}, + {value: 7, label: '鍓嶄竷鏈�'}, + {value: -1, label: '涓嬫湀'} + ] + }, + { + value: 'quarter', + label: '瀛�', + children: [ + {value: '0', label: '鏈搴�'}, + {value: 1, label: '涓婂搴�'}, + {value: -1, label: '涓嬪搴�'} + ] + }, + { + value: 'year', + label: '骞�', + children: [ + {value: '0', label: '鏈勾'}, + {value: 1, label: '鍘诲勾'}, + {value: -1, label: '鏄庡勾'} + ] + }, + { + value: 'customized', + label: '鑷畾涔�', + children: [ + {value: '[0, 0]', label: '浠婂ぉ'}, + {value: '[1, 1]', label: '鏄ㄥぉ'}, + {value: '[3, 0]', label: '杩戜笁澶�'}, + {value: '[7, 0]', label: '杩戜竷澶�'}, + {value: '[30, 0]', label: '杩�30澶�'}, + {value: '[7, -7]', label: '鍓嶅悗涓冨ぉ'}, + {value: '[30, -30]', label: '鍓嶅悗30澶�'}, + {value: '[90, -90]', label: '鍓嶅悗90澶�'}, + {value: '[-1, -1]', label: '鏄庡ぉ'}, + {value: '[-2, -2]', label: '鍚庡ぉ'} + ] + }, +] + +class MainSearch extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + formlist: PropTypes.any, // 琛ㄥ崟 + card: PropTypes.object, // 鎼滅储鏉′欢淇℃伅 + inputSubmit: PropTypes.any // 鍥炶溅鎻愪氦浜嬩欢 + } + + state = { + openType: null, // 鎼滅储鏉′欢鏄剧ず绫诲瀷 + resourceType: null, // 涓嬫媺鎼滅储鏃讹紝閫夐」鏉ユ簮绫诲瀷 + formlist: null, // 琛ㄥ崟 + textTooltip: '瀛楁鍚嶅彲浠ヤ娇鐢ㄩ�楀彿鍒嗛殧锛岃繘琛岀患鍚堟悳绱�', + } + + /** + * @description 琛ㄥ崟棰勫鐞� + * 1銆佹牴鎹〃鍗曠被鍨嬶紝鏄剧ず琛ㄥ崟鍙紪杈戦」 + * 2銆佷笅鎷夐�夋嫨锛屾牴鎹暟鎹簮绫诲瀷鏄剧ず鐩稿叧閰嶇疆 + */ + UNSAFE_componentWillMount () { + const { formlist, dict } = this.props + + let type = formlist.filter(cell => cell.key === 'type')[0].initVal + let _items = formlist.filter(cell => cell.key === 'items')[0].initVal + let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal + let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide'] // 榛樿鏄剧ず椤� + + if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮 + _options = [..._options, 'resourceType', 'options', 'display', 'quick'] + } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙� + _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database'] + } else if (type === 'group') { + _options = ['label', 'type', 'field', 'datefield', 'initval', 'blacklist', 'ratio', 'items', 'required', 'transfer'] + } + + if (type === 'select' || type === 'link') { + _options.push('setAll') + } + + if (type === 'link') { // 鍏宠仈绫诲瀷銆佸鍔犲叧鑱斾笂绾х殑瀛楁鍚� + _options = [..._options, 'linkField'] + } + + this.setState({ + openType: type, + items: _items, + resourceType: resourceType, + formlist: formlist.map(form => { + // 琛ㄥ崟涓哄垵濮嬪�煎瓧娈碉紝涓旀暟鎹被鍨嬪睘浜庢椂闂寸被鍨嬫椂锛岃缃垵濮嬪�间负涓嬫媺閫夋嫨锛屽苟閲嶇疆閫夋嫨椤� + if (form.key === 'initval' && dateOptions.hasOwnProperty(type)) { + form.options = dateOptions[type] + form.type = 'select' + } else if (form.key === 'initval' && type === 'group') { + form.options = groupOptions.filter(op => _items.includes(op.value)) + form.type = 'cascader' + } else if (form.key === 'match') { // 琛ㄥ崟涓哄尮閰嶅瓧娈垫椂锛屾牴鎹笉鍚岀殑绫诲瀷锛屾樉绀哄搴旂殑鍖归厤瑙勫垯 + if (type === 'text') { + form.options = matchReg.text + } else if (type === 'multiselect') { + form.options = matchReg.multiselect + } else if (type === 'select' || type === 'link') { + form.options = matchReg.select + } else if (type === 'date') { + form.options = matchReg.date + } else if (type === 'datemonth') { + form.options = matchReg.datemonth + } else if (type === 'dateweek' || type === 'daterange') { + form.options = matchReg.daterange + } + } else if (form.key === 'field' && type === 'text') { + form.tooltip = this.state.textTooltip + } else if (form.key === 'field' && type === 'group') { + form.label = dict['model.form.type'] + dict['model.form.field'] + } + form.hidden = !_options.includes(form.key) + return form + }) + }) + } + + componentDidMount () { + const { card } = this.props + + if (card.focus) { + try { + let _form = document.getElementById('label') + _form.select() + } catch { + console.warn('琛ㄥ崟focus澶辫触锛�') + } + } + } + + /** + * @description 鎼滅储鏉′欢绫诲瀷鍒囨崲 + */ + openTypeChange = (key, value) => { + const { dict } = this.props + const { resourceType, items } = this.state + + if (key === 'type') { + let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide'] + + if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '0') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮 + _options = [..._options, 'resourceType', 'options', 'display', 'quick'] + } else if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙� + _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database'] + } else if (value === 'group') { + _options = ['label', 'type', 'field', 'datefield', 'initval', 'items', 'ratio', 'blacklist', 'required', 'transfer'] + } + + if (value === 'select' || value === 'link') { + _options.push('setAll') + } + + if (value === 'link') { + _options = [..._options, 'linkField'] + } + + let matchs = [] + + this.setState({ + openType: value, + formlist: this.state.formlist.map(form => { + form.hidden = !_options.includes(form.key) // 闅愯棌琛ㄥ崟 + + if (form.key === 'initval') { + if (dateOptions.hasOwnProperty(value)) { // 鏍规嵁鎼滅储鏉′欢绫诲瀷锛岄�夋嫨鍒濆鍊肩殑绫诲瀷鍙婃暟鎹� + form.options = dateOptions[value] + form.type = 'select' + } else if (value === 'group') { + form.options = groupOptions.filter(op => items.includes(op.value)) + form.type = 'cascader' + } else { + form.type = 'text' + } + } else if (form.key === 'match') { // 鎼滅储鏉′欢绫诲瀷鍒囨崲鏃讹紝鍖归厤瑙勫垯绫诲瀷瀵瑰簲鍒囨崲 + if (value === 'text') { + form.options = matchReg.text + } else if (value === 'multiselect') { + form.options = matchReg.multiselect + } else if (value === 'select' || value === 'link') { + form.options = matchReg.select + } else if (value === 'date') { + form.options = matchReg.date + } else if (value === 'datemonth') { + form.options = matchReg.datemonth + } else if (value === 'dateweek' || value === 'daterange') { + form.options = matchReg.daterange + } + matchs = form.options + } else if (form.key === 'field') { + form.tooltip = '' + form.label = dict['model.form.field'] + if (value === 'text') { + form.tooltip = this.state.textTooltip + } else if (value === 'group') { + form.label = dict['model.form.type'] + dict['model.form.field'] + } + } + + return form + }) + }, () => { + if (this.props.form.getFieldValue('initval') !== undefined) { + this.props.form.setFieldsValue({initval: ''}) + } + if (this.props.form.getFieldValue('match') !== undefined) { + this.props.form.setFieldsValue({match: matchs[0].value}) + } + }) + } + } + + /** + * @description 鏁版嵁婧愮被鍨嬪垏鎹� + */ + onChange = (e, key) => { + const { openType } = this.state + let value = e.target.value + + if (key === 'resourceType') { + let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'display', 'ratio', 'blacklist', 'required', 'Hide'] + + if (value === '0') { + _options = [..._options, 'options', 'quick'] + } else if (value === '1') { + _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database'] + } + + if (openType === 'select' || openType === 'link') { + _options.push('setAll') + } + + if (openType === 'link') { + _options = [..._options, 'linkField'] + } + + this.setState({ + resourceType: value, + formlist: this.state.formlist.map(form => { + form.hidden = !_options.includes(form.key) + return form + }) + }) + } + } + + checkChange = (values, key) => { + const { openType, formlist } = this.state + + if (key === 'items') { + this.setState({ + items: values, + formlist: formlist.map(form => { + if (form.key === 'initval' && openType === 'group') { + form.options = groupOptions.filter(op => values.includes(op.value)) + } + + return form + }) + }) + + let _initval = this.props.form.getFieldValue('initval') + if (_initval && !values.includes(_initval[0])) { + this.props.form.setFieldsValue({initval: ''}) + } + } + } + + handleSubmit = (e) => { + e.preventDefault() + + if (this.props.inputSubmit) { + this.props.inputSubmit() + } + } + + getFields() { + const { openType } = this.state + const { getFieldDecorator } = this.props.form + const fields = [] + this.state.formlist.forEach((item, index) => { + if (item.hidden) return + + if (item.type === 'text') { // 鏂囨湰鎼滅储 + let rules = [] + if (item.key === 'field' || item.key === 'datefield') { + rules = [{ + pattern: openType === 'text' ? formRule.field.multipattern : formRule.field.pattern, + message: formRule.field.message + }, { + max: formRule.field.max, + message: formRule.field.maxMessage + }] + } else { + rules = [{ + max: formRule.input.max, + message: formRule.input.message + }] + } + + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.tooltip ? + <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} 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="" 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) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0} + onChange={(value) => {this.openTypeChange(item.key, value)}} + getPopupContainer={() => document.getElementById('commontable-search-form-box')} + > + {item.options.map(option => + <Select.Option id={option.value} title={option.text} key={option.value} value={option.value}> + {item.key === 'icon' && <Icon type={option.text} />} {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.onChange(e, item.key)}}> + { + item.options.map(option => { + return ( + <Radio key={option.value} value={option.value}>{option.text}</Radio> + ) + }) + } + </Radio.Group>, + )} + </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 + '!' + } + ] + })(<CodeMirror />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'options') { + fields.push( + <Col span={20} offset={4} key={index}> + <EditTable data={item.initVal} type={this.state.openType} dict={this.props.dict} ref="editTable"/> + </Col> + ) + } else if (item.type === 'checkbox') { + 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 + '!' + } + ] + })( + <Checkbox.Group style={{width: '105%'}} options={item.options} onChange={(values) => this.checkChange(values, item.key)}/> + )} + </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> + ) + } else if (item.type === 'cascader') { // 澶氶�� + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.label}> + {getFieldDecorator(item.key, { + initialValue: item.initVal + })( + <Cascader options={item.options} placeholder="" /> + )} + </Form.Item> + </Col> + ) + } + }) + + return fields + } + + handleConfirm = () => { + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let isvalid = true + values.uuid = this.props.card.uuid + // 涓嬫媺鑿滃崟鎴栬仈鍔ㄨ彍鍗� + if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') { + values.options = this.refs.editTable.state.dataSource + values.dataSource = '' + let emptys = [] + if (values.type === 'multiselect' || values.type === 'select') { + emptys = values.options.filter(op => !(op.Value && op.Text)) + } else { + emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID)) + } + if (emptys.length > 0) { + isvalid = false + } + } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') { + values.options = [] + } + + if (isvalid) { + ['linkField', 'valueField', 'valueText', 'orderBy'].forEach(item => { + if (values[item]) { + values[item] = values[item].replace(/\s* | \t* | \v* | \r*/ig, '') + } + }) + + let error = Utils.verifySql(values.dataSource) + + if (error) { + notification.warning({ + top: 92, + message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error, + duration: 5 + }) + return + } + + resolve(values) + } else { + notification.warning({ + top: 92, + message: this.props.dict['model.form.selectItem.error'], + duration: 5 + }) + } + } else { + reject(err) + } + }) + }) + } + + render() { + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + return ( + <Form {...formItemLayout} className="model-search-edit-form" id="commontable-search-form-box"> + <Row gutter={24}>{this.getFields()}</Row> + </Form> + ) + } +} + +export default Form.create()(MainSearch) \ No newline at end of file diff --git a/src/menu/searchcomponent/searchform/index.scss b/src/menu/searchcomponent/searchform/index.scss new file mode 100644 index 0000000..cc9c99c --- /dev/null +++ b/src/menu/searchcomponent/searchform/index.scss @@ -0,0 +1,32 @@ +.model-search-edit-form { + min-height: 180px; + .ant-col-offset-4 { + padding-left: 6px!important; + padding-bottom: 20px; + } + .ant-form-item.text-area { + margin-bottom: 0px; + .ant-form-item-control-wrapper { + width: 100%; + } + .CodeMirror { + height: 150px; + } + } + .anticon-question-circle { + color: #c49f47; + position: relative; + left: -3px; + } + .ant-input-number { + width: 100%; + } + .ant-checkbox-group { + .ant-checkbox-group-item { + .ant-checkbox + span { + padding-left: 4px; + padding-right: 4px; + } + } + } +} \ No newline at end of file diff --git a/src/tabviews/zshare/normalTable/index.jsx b/src/tabviews/zshare/normalTable/index.jsx index cddb597..5eb8327 100644 --- a/src/tabviews/zshare/normalTable/index.jsx +++ b/src/tabviews/zshare/normalTable/index.jsx @@ -670,8 +670,8 @@ return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>) }) } else if (type === 'horizontal') { - return contents.map((content, index) => { - return (<span key={index}>{content}</span>) + return contents.map((cont, index) => { + return (<span key={index}>{cont.content}</span>) }) } else if (type === 'vertical2') { return ( diff --git a/src/templates/sharecomponent/chartcomponent/index.jsx b/src/templates/sharecomponent/chartcomponent/index.jsx index b4eed38..c9b6726 100644 --- a/src/templates/sharecomponent/chartcomponent/index.jsx +++ b/src/templates/sharecomponent/chartcomponent/index.jsx @@ -531,11 +531,6 @@ type: 'overlap' } setting.offset = 0 - // setting.style = { - // textAlign: 'center', - // fontSize: 12, - // fill: '#535353' - // } } _chart.label('percent', setting) diff --git a/src/templates/sharecomponent/tablecomponent/index.jsx b/src/templates/sharecomponent/tablecomponent/index.jsx index 05bcaa8..543f4ee 100644 --- a/src/templates/sharecomponent/tablecomponent/index.jsx +++ b/src/templates/sharecomponent/tablecomponent/index.jsx @@ -165,11 +165,11 @@ }) let _config = {...config, tables: [...selectedTables, _table]} - + Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => { if (res.status) { let tabmsg = { - tableName: _table.name, + tableName: _table.TbName, columns: res.FDName.map(item => { let _type = item.FieldType.toLowerCase() let _decimal = 0 diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx index 79bd9e8..e78a014 100644 --- a/src/views/menudesign/index.jsx +++ b/src/views/menudesign/index.jsx @@ -22,6 +22,7 @@ const MenuForm = asyncComponent(() => import('@/menu/menuform')) const SourceWrap = asyncComponent(() => import('@/menu/modelsource')) const MenuShell = asyncComponent(() => import('@/menu/menushell')) +// const Controller = asyncComponent(() => import('@/mob/controller')) // const DataSource = asyncComponent(() => import('@/mob/datasource')) const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent')) @@ -39,6 +40,7 @@ } UNSAFE_componentWillMount() { + this.getMenuParam() // this.testFunc() } @@ -50,6 +52,10 @@ this.setState = () => { return } + } + + reloadTab = () => { + } closeView = () => { @@ -155,6 +161,8 @@ config: fromJS(config).toJS(), openEdition: result.open_edition || '', }) + + this.getRoleFields() } else { notification.warning({ top: 92, @@ -162,6 +170,44 @@ duration: 5 }) } + }) + } + + getRoleFields = () => { + Api.getSystemConfig({func: 'sPC_Get_Roles_sModular'}).then(res => { + if (res.status) { + let _permFuncField = [] + let _sysRoles = [] + + if (res.Roles && res.Roles.length > 0) { + _sysRoles = res.Roles.map(role => { + return { + uuid: Utils.getuuid(), + value: role.RoleID, + text: role.RoleName + } + }) + } + + if (res.sModular && res.sModular.length > 0) { + res.sModular.forEach(field => { + if (field.ModularNo) { + _permFuncField.push(field.ModularNo) + } + }) + _permFuncField = _permFuncField.sort() + } + + this.setState({ + config: {...this.state.config, sysRoles: _sysRoles, permFuncField: _permFuncField} + }) + } + }) + } + + initMenuList = (list) => { + this.setState({ + config: {...this.state.config, fstMenuList: list} }) } @@ -212,6 +258,8 @@ updatetable = (config, fields) => { const { tableFields } = this.state + config.tableFields = fields ? fields : tableFields + this.setState({ config: config, tableFields: fields ? fields : tableFields @@ -240,22 +288,26 @@ parentId={this.props.match.params.ParentId} MenuName={this.props.match.params.MenuName} MenuNo={this.props.match.params.MenuNo} + initMenuList={this.initMenuList} updateConfig={this.updateConfig} /> {/* 琛ㄥ悕娣诲姞 */} - {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null} + {config ? <TableComponent config={config} updatetable={this.updatetable}/> : null} </Panel> {/* 缁勪欢娣诲姞 */} <Panel header={dict['mob.component']} key="component"> <SourceWrap /> </Panel> + {/* <Panel header={dict['mob.style']} key="style"> + <Controller /> + </Panel> */} </Collapse> </div> <div className="menu-view"> <Card title={ <div> {config && config.MenuName} - <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={() => this.reloadTab(true)} /> + <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={() => this.reloadTab()} /> </div> } bordered={false} extra={ <div> @@ -263,7 +315,7 @@ <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{dict['mob.save']}</Button> </div> } style={{ width: '100%' }}> - {config ? <MenuShell config={config} handleList={this.updateConfig} /> : null} + {config ? <MenuShell config={config} handleList={this.updateConfig} deleteCard={this.deleteCard} /> : null} </Card> </div> </div> -- Gitblit v1.8.0