From a181fc113d024ed34d6b488c65882961bd1de3f4 Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期二, 02 六月 2020 19:00:57 +0800 Subject: [PATCH] 2020-06-02 --- src/components/tabview/index.jsx | 7 src/tabviews/treepage/index.jsx | 882 ++++++++++++ src/tabviews/formtab/index.jsx | 6 src/templates/formtabconfig/index.jsx | 4 src/templates/comtableconfig/index.jsx | 9 src/templates/treepageconfig/index.jsx | 921 ++++++++++++ src/templates/zshare/editcomponent/index.jsx | 4 src/locales/zh-CN/model.js | 1 src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.scss | 31 src/templates/treepageconfig/source.jsx | 57 src/locales/en-US/model.js | 1 src/templates/menuconfig/editthdmenu/index.jsx | 11 src/templates/formtabconfig/source.jsx | 2 src/tabviews/subtable/index.jsx | 6 src/templates/sharecomponent/tabscomponent/tabform/index.scss | 11 src/tabviews/commontable/index.jsx | 75 src/templates/treepageconfig/index.scss | 266 +++ src/templates/sharecomponent/tabscomponent/index.jsx | 49 src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx | 12 src/utils/utils.js | 8 src/templates/zshare/formconfig.jsx | 311 ++++ src/templates/sharecomponent/tabscomponent/tabform/index.jsx | 46 src/tabviews/managetable/index.jsx | 6 src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.jsx | 250 +++ src/templates/subtableconfig/index.jsx | 12 src/tabviews/zshare/cardcomponent/index.scss | 4 src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx | 765 ++++++++++ src/templates/sharecomponent/treesettingcomponent/index.scss | 42 src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx | 51 src/tabviews/treepage/index.scss | 168 ++ src/tabviews/zshare/cardcomponent/index.jsx | 3 src/templates/sharecomponent/treesettingcomponent/index.jsx | 181 ++ src/utils/option.js | 7 src/templates/sharecomponent/treesettingcomponent/settingform/index.scss | 45 34 files changed, 4,163 insertions(+), 91 deletions(-) diff --git a/src/components/tabview/index.jsx b/src/components/tabview/index.jsx index 2637efe..25a6af6 100644 --- a/src/components/tabview/index.jsx +++ b/src/components/tabview/index.jsx @@ -18,6 +18,7 @@ const Home = asyncComponent(() => import('@/tabviews/home')) const CommonTable = asyncComponent(() => import('@/tabviews/commontable')) +const TreePage = asyncComponent(() => import('@/tabviews/treepage')) const VerupTable = asyncComponent(() => import('@/tabviews/verupmanage')) const ScriptTable = asyncComponent(() => import('@/tabviews/scriptmanage')) const TabManage = asyncComponent(() => import('@/tabviews/tabmanage')) @@ -102,6 +103,8 @@ return (<Home MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>) } else if (view.type === 'CommonTable') { return (<CommonTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>) + } else if (view.type === 'TreePage') { + return (<TreePage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>) } else if (view.type === 'VerupTable') { return (<VerupTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>) } else if (view.type === 'ScriptTable') { @@ -210,7 +213,7 @@ className="test" tab={ <span className="tab-control"> - {['CommonTable', 'FormTab'].includes(view.type) ? + {['CommonTable', 'FormTab', 'TreePage'].includes(view.type) ? <Icon type="redo" onClick={(e) => {this.refreshTabview(e, view)}}/> : null } <span className="tab-name" onClick={(e) => {this.changeTab(e, view)}}> @@ -224,7 +227,7 @@ key={view.MenuID} > {this.selectcomponent(view)} - {view.type !== 'CommonTable' && view.type !== 'ManageTable' ? + {!['CommonTable', 'TreePage', 'ManageTable'].includes(view.type) ? <Button icon="copy" shape="circle" diff --git a/src/locales/en-US/model.js b/src/locales/en-US/model.js index fe21365..3004e65 100644 --- a/src/locales/en-US/model.js +++ b/src/locales/en-US/model.js @@ -82,6 +82,7 @@ 'header.form.refresh.view': 'Refresh the page', 'header.form.refresh.grid': 'Refresh the table', 'header.form.refresh.maingrid': '鍒锋柊涓昏〃', + 'header.form.refresh.mainline': '鍒锋柊涓昏〃锛堣锛�', 'header.form.refresh.equaltab': '鍒锋柊鍚岀骇鏍囩', 'header.form.refresh.subgrid': '鍒锋柊瀛愯〃', 'header.form.popClose': '鏍囩鍏抽棴', diff --git a/src/locales/zh-CN/model.js b/src/locales/zh-CN/model.js index 654bb1d..d235390 100644 --- a/src/locales/zh-CN/model.js +++ b/src/locales/zh-CN/model.js @@ -82,6 +82,7 @@ 'header.form.refresh.view': '鍒锋柊椤甸潰', 'header.form.refresh.grid': '鍒锋柊琛ㄦ牸', 'header.form.refresh.maingrid': '鍒锋柊涓昏〃', + 'header.form.refresh.mainline': '鍒锋柊涓昏〃锛堣锛�', 'header.form.refresh.equaltab': '鍒锋柊鍚岀骇鏍囩', 'header.form.refresh.subgrid': '鍒锋柊瀛愯〃', 'header.form.popClose': '鏍囩鍏抽棴', diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx index 9d3881e..0815699 100644 --- a/src/tabviews/commontable/index.jsx +++ b/src/tabviews/commontable/index.jsx @@ -173,6 +173,8 @@ config.tabgroups.forEach(group => { group.sublist = group.sublist.filter(tab => permAction[tab.linkTab]) }) + // 鍘婚櫎绌鸿鏍囩 + config.tabgroups = config.tabgroups.filter(group => group.sublist.length > 0) // 瑙嗗浘鏉冮檺 config.charts = config.charts.filter(item => { @@ -255,7 +257,6 @@ let _tabActive = {} // 绛涢�夊睍寮�鐨則ab椤� config.tabgroups.forEach(group => { - if (group.sublist.length === 0) return _tabActive[group.uuid] = group.sublist[0].uuid }) @@ -928,9 +929,11 @@ handleMainTable = (type, tab) => { if (type === 'maingrid' && tab.supMenu === 'mainTable') { this.reloadtable() - } else if (type === 'maingrid' && tab.supMenu) { + } else if (type === 'mainline' && tab.supMenu === 'mainTable') { + this.reloadtable() + } else if ((type === 'maingrid' || type === 'mainline') && tab.supMenu) { this.setState({ - refreshtabs: [tab.supMenu] + refreshtabs: [type, tab.supMenu] }, () => { this.setState({ refreshtabs: null @@ -1445,41 +1448,37 @@ })} </div> : null } {setting && setting.onload !== 'false' && - config.tabgroups.map(group => { - if (group.sublist.length === 0) return null - - return ( - <Tabs activeKey={tabActive[group.uuid]} key={group.uuid} onChange={(key) => this.setState({tabActive: {...tabActive, [group.uuid]: key}})}> - {group.sublist.map(_tab => { - return ( - <TabPane tab={ - <span> - {_tab.icon ? <Icon type={_tab.icon} /> : null} - {_tab.label} - </span> - } key={_tab.uuid}> - {_tab.type === 'SubTable' ? - <SubTable - Tab={_tab} - menuType="main" - MenuID={_tab.linkTab} - mainSearch={_tab.searchPass === 'true' ? search : null} - userConfig={userConfig ? userConfig[_tab.uuid] : null} - triggerBtn={triggerBtn} - SupMenuID={this.props.MenuID} - refreshtabs={this.state.refreshtabs} - ContainerId={this.state.ContainerId} - BID={this.state.BIDs[_tab.supMenu] || ''} - BData={this.state.BIDs[_tab.supMenu + 'data'] || ''} - handleTableId={this.handleTableId} - handleMainTable={(type) => this.handleMainTable(type, _tab)} - /> : null} - </TabPane> - ) - })} - </Tabs> - ) - }) + config.tabgroups.map(group => ( + <Tabs activeKey={tabActive[group.uuid]} key={group.uuid} onChange={(key) => this.setState({tabActive: {...tabActive, [group.uuid]: key}})}> + {group.sublist.map(_tab => { + return ( + <TabPane tab={ + <span> + {_tab.icon ? <Icon type={_tab.icon} /> : null} + {_tab.label} + </span> + } key={_tab.uuid}> + {_tab.type === 'SubTable' ? + <SubTable + Tab={_tab} + menuType="main" + MenuID={_tab.linkTab} + mainSearch={_tab.searchPass === 'true' ? search : null} + userConfig={userConfig ? userConfig[_tab.uuid] : null} + triggerBtn={triggerBtn} + SupMenuID={this.props.MenuID} + refreshtabs={this.state.refreshtabs} + ContainerId={this.state.ContainerId} + BID={this.state.BIDs[_tab.supMenu] || ''} + BData={this.state.BIDs[_tab.supMenu + 'data'] || ''} + handleTableId={this.handleTableId} + handleMainTable={(type) => this.handleMainTable(type, _tab)} + /> : null} + </TabPane> + ) + })} + </Tabs>) + ) } <Button icon="copy" diff --git a/src/tabviews/formtab/index.jsx b/src/tabviews/formtab/index.jsx index f185a68..4bf485d 100644 --- a/src/tabviews/formtab/index.jsx +++ b/src/tabviews/formtab/index.jsx @@ -570,11 +570,11 @@ * @description 瀛愯〃鎿嶄綔瀹屾垚鍚庡埛鏂颁富琛� */ handleMainTable = (type, tab) => { - if (type === 'maingrid' && tab.supMenu === 'mainTable') { + if ((type === 'maingrid' || type === 'mainline') && tab.supMenu === 'mainTable') { this.loadmaindata() - } else if (type === 'maingrid' && tab.supMenu) { + } else if ((type === 'maingrid' || type === 'mainline') && tab.supMenu) { this.setState({ - refreshtabs: [tab.supMenu] + refreshtabs: [type, tab.supMenu] }, () => { this.setState({ refreshtabs: null diff --git a/src/tabviews/managetable/index.jsx b/src/tabviews/managetable/index.jsx index 278fa94..991c009 100644 --- a/src/tabviews/managetable/index.jsx +++ b/src/tabviews/managetable/index.jsx @@ -644,9 +644,11 @@ handleMainTable = (type, tab) => { if (type === 'maingrid' && tab.supMenu === 'mainTable') { this.reloadtable() - } else if (type === 'maingrid' && tab.supMenu) { + } else if (type === 'mainline' && tab.supMenu === 'mainTable') { + this.reloadtable() + } else if ((type === 'maingrid' || type === 'mainline') && tab.supMenu) { this.setState({ - refreshtabs: [tab.supMenu] + refreshtabs: [type, tab.supMenu] }, () => { this.setState({ refreshtabs: null diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx index c11b488..c78e7bc 100644 --- a/src/tabviews/subtable/index.jsx +++ b/src/tabviews/subtable/index.jsx @@ -469,6 +469,7 @@ let _BID = this.props.BID let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0)) + let prex = this.props.Tab && this.props.Tab.label ? this.props.Tab.label + '-' : '' if (requireFields.length > 0) { let labels = requireFields.map(item => item.label) @@ -476,7 +477,7 @@ notification.warning({ top: 92, - message: this.state.dict['form.required.input'] + labels.join('銆�') + ' !', + message: prex + this.state.dict['form.required.input'] + labels.join('銆�') + ' !', duration: 3 }) return @@ -522,7 +523,6 @@ this.setState({ loading: false }) - let prex = this.props.Tab && this.props.Tab.label ? this.props.Tab.label + ': ' : '' notification.error({ top: 92, @@ -800,6 +800,8 @@ } else if (btn.execSuccess === 'equaltab' && type === 'success') { this.reloadtable() this.props.handleMainTable('equaltab') + }else if (btn.execSuccess === 'mainline' && type === 'success') { + this.props.handleMainTable('mainline') } } diff --git a/src/tabviews/treepage/index.jsx b/src/tabviews/treepage/index.jsx new file mode 100644 index 0000000..462efa1 --- /dev/null +++ b/src/tabviews/treepage/index.jsx @@ -0,0 +1,882 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' +import { is, fromJS } from 'immutable' +import { notification, Spin, Tabs, Icon, Modal, Button, message, Tree, Typography, Row, Col, Card, Input, Empty } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import zhCN from '@/locales/zh-CN/main.js' +import enUS from '@/locales/en-US/main.js' +import Utils from '@/utils/utils.js' +import asyncComponent from '@/utils/asyncComponent' +import asyncSpinComponent from '@/utils/asyncSpinComponent' +import {refreshTabView, modifyTabview} from '@/store/action' + +import NotFount from '@/components/404' +import './index.scss' + +const VerifyCard = asyncComponent(() => import('@/tabviews/zshare/verifycard')) +const SubTable = asyncSpinComponent(() => import('@/tabviews/subtable')) + +const { TabPane } = Tabs +const { TreeNode } = Tree +const { Search } = Input +const { Paragraph } = Typography + +class TreePage extends Component { + static propTpyes = { + MenuID: PropTypes.string, // 鑿滃崟Id + MenuNo: PropTypes.string, // 鑿滃崟鍙傛暟 + MenuName: PropTypes.string // 鑿滃崟鍚嶇О + } + + state = { + dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + ContainerId: Utils.getuuid(), // 鑿滃崟澶栧眰html Id + loadingview: true, // 椤甸潰鍔犺浇涓� + viewlost: false, // 椤甸潰涓㈠け锛�1銆佹湭鑾峰彇鍒伴厤缃�-椤甸潰涓㈠け锛�2銆侀〉闈㈡湭鍚敤 + lostmsg: '', // 椤甸潰涓㈠け鏃剁殑鎻愮ず淇℃伅 + config: {}, // 椤甸潰閰嶇疆淇℃伅锛屽寘鎷寜閽�佹悳绱€�佹樉绀哄垪銆佹爣绛剧瓑 + userConfig: null, // 鐢ㄦ埛鑷畾涔夎缃� + userParam: null, // 淇濆瓨鐢ㄦ埛缂栬緫涓殑閰嶇疆 + setting: null, // 椤甸潰鍏ㄥ眬璁剧疆锛氭暟鎹簮銆佹寜閽強鏄剧ず鍒楀浐瀹氥�佷富閿瓑 + treedata: null, // 鍒楄〃鏁版嵁闆� + treeNodes: null, // 鍒楄〃鏁版嵁闆� + loading: false, // 鍒楄〃鏁版嵁鍔犺浇涓� + BIDs: {}, // 涓婄骇琛╥d + visible: false, // 寮规鏄剧ず闅愯棌鎺у埗 + treevisible: false, // 鑿滃崟缁撴瀯鏍戝脊妗嗘樉绀洪殣钘忔帶鍒� + refreshtabs: null, // 闇�瑕佸埛鏂扮殑鏍囩闆� + confirmLoading: false,// 鑷畾涔夎缃ā鎬佹鍔犺浇涓� + revertLoading: false, // 鎭㈠榛樿璁剧疆 + settingVisible: false,// 鑷畾涔夎缃ā鎬佹 + triggerBtn: null, // 鐐瑰嚮琛ㄦ牸涓垨蹇嵎閿Е鍙戠殑鎸夐挳 + tabActive: null, // 鏍囩椤靛睍寮�鎺у埗 + } + + /** + * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅 + */ + async loadconfig () { + const { permAction } = this.props + + let _param = { + func: 'sPC_Get_LongParam', + MenuID: this.props.MenuID + } + let result = await Api.getSystemCacheConfig(_param) + + if (result.status) { + let config = '' + let userConfig = null + let _curUserConfig = '' + + try { // 閰嶇疆淇℃伅瑙f瀽 + config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) + } catch (e) { + console.warn('Parse Failure') + config = '' + } + + if (result.LongParamUser) { + try { // 閰嶇疆淇℃伅瑙f瀽 + userConfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParamUser))) + _curUserConfig = userConfig[this.props.MenuID] + } catch (e) { + console.warn('Parse Failure') + userConfig = null + } + } + + // 椤甸潰閰嶇疆瑙f瀽閿欒鏃舵彁绀� + if (!config) { + this.setState({ + loadingview: false, + viewlost: true + }) + return + } + + // 椤甸潰鏈惎鐢ㄦ椂锛屾樉绀烘湭鍚敤椤甸潰 + if (!config.enabled) { + this.setState({ + loadingview: false, + viewlost: true, + lostmsg: this.state.dict['main.view.unenabled'] + }) + return + } + + // 鏉冮檺杩囨护 + config.tabgroups.forEach(group => { + group.sublist = group.sublist.filter(tab => permAction[tab.linkTab]) + }) + config.tabgroups = config.tabgroups.filter(group => group.sublist.length > 0) + + if (_curUserConfig) { + config.setting = {...config.setting, ..._curUserConfig.setting} + config.easyCode = _curUserConfig.easyCode || config.easyCode || '' + } + + let _tabActive = {} // 绛涢�夊睍寮�鐨則ab椤� + let _tabgroups = [] + + config.tabgroups.forEach(group => { + let _group = fromJS(group).toJS() + _group.sublist = _group.sublist.filter(tab => !tab.level) + + if (_group.sublist.length > 0) { + _tabActive[_group.uuid] = _group.sublist[0].uuid + _tabgroups.push(_group) + } + }) + + this.setState({ + loadingview: false, + config: config, + tabActive: _tabActive, + userConfig: userConfig, + setting: config.setting, + tabgroups: _tabgroups + }, () => { + this.loadmaindata() + this.setShortcut() + }) + } else { + this.setState({ + loadingview: false, + viewlost: true + }) + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + } + } + + setShortcut = () => { + const { userConfig, config } = this.state + if (!userConfig) return + + document.onkeydown = (event) => { + let e = event || window.event + let keyCode = e.keyCode || e.which || e.charCode + let preKey = '' + + if (e.ctrlKey) { + preKey = 'ctrl' + } else if (e.shiftKey) { + preKey = 'shift' + } else if (e.altKey) { + preKey = 'alt' + } + + if (!preKey) return + + let istrigger = false + + Object.keys(userConfig).forEach(key => { + if (key === this.props.MenuID || !userConfig[key].action || istrigger) return + + let _actions = userConfig[key].action + + Object.keys(_actions).forEach(btnkey => { + let item = _actions[btnkey] + + if (!item.shortcut || typeof(item.shortcut) !== 'object' || item.shortcut.length === 0 || istrigger) return + + if (preKey === item.shortcut[0] && keyCode === item.shortcut[1]) { + e.preventDefault() + istrigger = true + + let _groupId = '' + let _ActiveTabId = '' + config.tabgroups.forEach(group => { + if (group.sublist.length === 0) return + + let _tab = group.sublist.filter(tab => tab.uuid === key)[0] + if (_tab) { + _groupId = group.uuid + _ActiveTabId = _tab.uuid + } + }) + + if (this.state.tabActive[_groupId] === _ActiveTabId) { + this.setState({ + triggerBtn: { + uuid: new Date().getTime(), + parentId: key, + button: {...item, uuid: btnkey}, + data: null + } + }) + } else { + this.setState({ + tabActive: {...this.state.tabActive, [_groupId]: _ActiveTabId} + }, () => { + this.setState({ + triggerBtn: { + uuid: new Date().getTime(), + parentId: key, + button: {...item, uuid: btnkey}, + data: null + } + }) + }) + } + } + }) + }) + } + } + + /** + * @description 涓昏〃鏁版嵁鍔犺浇 + */ + async loadmaindata () { + const { setting, BIDs } = this.state + let param = '' + + this.setState({ + loading: true + }) + + if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) { + param = this.getCustomParam() + } else { + param = this.getDefaultParam() + } + + this.handleTableId('mainTable', '', '') + + if (!param) { // 鏈幏鍙栧弬鏁版椂锛屼笉鍙戣姹� + return + } + + let result = await Api.genericInterface(param) + if (result.status) { + let parentNodes = [] + let _options = [] + result.data.forEach(item => { + let pval = item[setting.parentField] + let val = item[setting.valueField] + + if (!val) return + + if (pval === setting.mark) { + parentNodes.push({ + title: item[setting.labelField] || '', + key: val, + parentId: '', + level: 1 + }) + } else if (pval) { + _options.push({ + title: item[setting.labelField] || '', + key: val, + parentId: pval + }) + } + }) + let _treedata = this.getTree(parentNodes, _options) + + this.setState({ + treedata: _treedata, + treeNodes: fromJS(_treedata).toJS(), + loading: false, + BIDs: { + ...BIDs, + mainTable: '' + } + }) + } else { + this.setState({ + loading: false, + treeNodes: [], + treedata: [] + }) + notification.error({ + top: 92, + message: result.message, + duration: 10 + }) + } + } + + /** + * @description 鑾峰彇缁撴瀯鏍戜俊鎭� + */ + getTree = (parents, options) => { + parents.forEach(parent => { + parent.children = [] + // 娣诲姞鑿滃崟鐨勫瓙鍏冪礌 + options = options.filter(option => { + if (option.parentId === parent.key) { + option.level = parent.level + 1 + + parent.children.push(option) + return false + } + return true + }) + + if (parent.children.length === 0) { + parent.children = null + } else { + parent.children = this.getTree(parent.children, options) + } + }) + return parents + } + + /** + * @description 鑾峰彇鏍戣妭鐐� + */ + renderTreeNodes = (nodes) => { + return nodes.map(item => { + if (item.children) { + return ( + <TreeNode icon={<Icon type="folder-open" />} title={item.title} key={item.key} dataRef={item}> + {this.renderTreeNodes(item.children)} + </TreeNode> + ) + } + return <TreeNode icon={<Icon type="file" />} key={item.key} title={item.title} dataRef={item} isLeaf /> + }) + } + + selectTreeNode = (selectedKeys, {selected, node}) => { + const { config } = this.state + + let selectId = selectedKeys[0] + let _data = fromJS(node.props.dataRef).toJS() + delete _data.children + + let _tabgroups = [] + let _tabActive = {} + + config.tabgroups.forEach(group => { + let _group = fromJS(group).toJS() + _group.sublist = _group.sublist.filter(tab => !tab.level || (selected && tab.level === _data.level)) + + if (_group.sublist.length > 0) { + _tabActive[_group.uuid] = _group.sublist[0].uuid + _tabgroups.push(_group) + } + }) + + this.setState({ + tabgroups: _tabgroups, + tabActive: _tabActive + }) + + if (selected) { + this.handleTableId('mainTable', selectId, _data) + } else { + this.handleTableId('mainTable', '', '') + } + } + + /** + * @description 鑾峰彇鐢ㄦ埛鑷畾涔夊瓨鍌ㄨ繃绋嬩紶鍙� + */ + getCustomParam = () => { + const { setting } = this.state + + let param = { + OrderCol: setting.order, + dataM: this.props.dataManager ? 'Y' : '', + } + + if (setting.interType === 'inner') { + param.func = setting.innerFunc + } else { + if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) { + param.rduri = window.GLOB.mainSystemApi + } else if (setting.sysInterface !== 'true') { + param.rduri = setting.interface + } + + if (setting.outerFunc) { + param.func = setting.outerFunc + } + } + + return param + } + + /** + * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁� + */ + getDefaultParam = () => { + const { setting } = this.state + + let arr_field = `${setting.valueField},${setting.labelField},${setting.parentField}` + + let param = { + func: 'sPC_Get_TableData', + obj_name: 'data', + arr_field: arr_field, + custom_script: setting.customScript || '', + default_sql: setting.default || 'true', + dataM: this.props.dataManager ? 'Y' : '' + } + + let _dataresource = setting.dataresource + + if (/\s/.test(_dataresource)) { + _dataresource = '(' + _dataresource + ') tb' + } + + if (this.props.dataManager) { // 鏁版嵁鏉冮檺 + _dataresource = _dataresource.replace(/\$@/ig, '/*') + _dataresource = _dataresource.replace(/@\$/ig, '*/') + param.custom_script = param.custom_script.replace(/\$@/ig, '/*') + param.custom_script = param.custom_script.replace(/@\$/ig, '*/') + } else { + _dataresource = _dataresource.replace(/@\$|\$@/ig, '') + param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '') + } + + let LText = '' + + if (setting.default !== 'false') { + LText = `select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows` + } + + if (param.custom_script) { + param.custom_script = param.custom_script.replace(/@orderBy@/ig, setting.order) + + if (LText) { + LText += ` + aaa: + if @ErrorCode!='' + insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@ + ` + } else { + param.custom_script += ` + aaa: + if @ErrorCode!='' + insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@ + ` + } + + param.custom_script = Utils.formatOptions(param.custom_script) + } + + param.LText = Utils.formatOptions(LText) + param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + param.secretkey = Utils.encrypt(param.LText, param.timestamp) + param.DateCount = '' + + return param + } + + /** + * @description 椤甸潰鍒锋柊锛岄噸鏂拌幏鍙栭厤缃� + */ + reloadview = () => { + this.setState({ + loadingview: true, + viewlost: false, + lostmsg: '', + config: {}, + userConfig: null, + userParam: null, + setting: null, + treedata: null, + treeNodes: null, + loading: false, + BIDs: {}, + }, () => { + this.loadconfig() + }) + } + + /** + * @description 琛ㄦ牸鍒锋柊 + */ + reloadtable = () => { + this.setState({ + pageIndex: 1 + }, () => { + this.loadmaindata() + }) + } + + /** + * @description 瀛愯〃鎿嶄綔瀹屾垚鍚庡埛鏂颁富琛� + */ + handleMainTable = (type, tab) => { + if (type === 'maingrid' && tab.supMenu === 'mainTable') { + this.reloadtable() + } else if (type === 'mainline' && tab.supMenu === 'mainTable') { + this.reloadtable() + } else if ((type === 'maingrid' || type === 'mainline') && tab.supMenu) { + this.setState({ + refreshtabs: [type, tab.supMenu] + }, () => { + this.setState({ + refreshtabs: null + }) + }) + } else if (type === 'equaltab' && tab.equalTab && tab.equalTab.length > 0) { + this.setState({ + refreshtabs: tab.equalTab + }, () => { + this.setState({ + refreshtabs: null + }) + }) + } + } + + /** + * @description 琛ㄦ牸Id鍙樺寲 + */ + handleTableId = (type, id, data) => { + const { BIDs } = this.state + + this.setState({ + BIDs: { + ...BIDs, + [type]: id, + [type + 'data']: data + } + }) + } + + handleviewconfig = (e) => { + e.stopPropagation() + + const { MenuNo } = this.props + const { config } = this.state + + if (config && config.funcs && config.funcs.length > 0) { + this.setState({ + treevisible: true + }) + } else { + let oInput = document.createElement('input') + oInput.value = MenuNo || '' + document.body.appendChild(oInput) + oInput.select() + document.execCommand('Copy') + document.body.removeChild(oInput) + message.success(this.state.dict['main.copy.success']) + } + } + + getTreeNode = (data) => { + let _type = { + view: '椤甸潰', + btn: '鎸夐挳', + tab: '鏍囩' + } + + return data.map(item => { + let _title = _type[item.subtype] + let _others = [] + + _others.push( + (item.menuNo ? item.menuNo + '(鑿滃崟鍙傛暟)' : ''), + (item.tableName ? item.tableName + '(琛ㄥ悕) ' : ''), + (item.innerFunc ? item.innerFunc + '(鍐呴儴鍑芥暟) ' : ''), + (item.outerFunc ? item.outerFunc + '(澶栭儴鍑芥暟)' : '') + ) + _others = _others.filter(Boolean) + _others = _others.join('銆�') + + if (item.label) { + _title = _title + '(' + item.label + ')' + } + if (_others) { + _title = _title + ': ' + _others + } + + if (item.subfuncs && item.subfuncs.length > 0) { + return ( + <TreeNode title={_title} key={item.uuid} dataRef={item} selectable={false}> + {this.getTreeNode(item.subfuncs)} + </TreeNode> + ) + } + return <TreeNode key={item.uuid} title={_title} isLeaf selectable={false} /> + }) + } + + controlCustomSetting = () => { + this.setState({ + settingVisible: true, + confirmLoading: false, + revertLoading: false + }) + } + + changeMenuParam = (param) => { + this.setState({userParam: param}) + } + + settingRevert = () => { + let param = { + func: 's_TrdMenu_UserParam_del', + MenuID: this.props.MenuID + } + this.setState({ + revertLoading: true + }) + + Api.getSystemConfig(param).then(result => { + if (!result.status) { + this.setState({ + revertLoading: false + }) + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + return + } + this.setState({ + settingVisible: false, + revertLoading: false + }, () => { + window.GLOB.CacheMap = new Map() + this.reloadview() + }) + }) + } + + settingSubmit = () => { + const { userParam } = this.state + let _LongParam = '' + + try { + _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(userParam))) + } catch (e) { + notification.warning({ + top: 92, + message: '缂栬瘧閿欒', + duration: 5 + }) + return + } + + let easyCode = userParam[this.props.MenuID] ? userParam[this.props.MenuID].easyCode : '' + + let param = { + func: 'sPC_TrdMenu_UserParam', + MenuID: this.props.MenuID, + EasyCode: easyCode || '', + LongParam: _LongParam + } + + this.setState({ + confirmLoading: true + }) + + Api.getSystemConfig(param).then(result => { + if (!result.status) { + this.setState({ + confirmLoading: false + }) + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + return + } + this.setState({ + settingVisible: false, + confirmLoading: false + }, () => { + window.GLOB.CacheMap = new Map() + this.reloadview() + }) + }) + } + + UNSAFE_componentWillMount () { + // 缁勪欢鍔犺浇鏃讹紝鑾峰彇鑿滃崟鏁版嵁 + this.loadconfig() + } + + UNSAFE_componentWillReceiveProps(nextProps) { + if (nextProps.refreshTab && nextProps.refreshTab.MenuID === this.props.MenuID) { + if (nextProps.refreshTab.position === 'view') { + this.reloadview() + } + this.props.refreshTabView('') + } else if (!is(fromJS(this.props.tabviews), fromJS(nextProps.tabviews))) { + let selectTab = nextProps.tabviews.filter(tab => tab.selected)[0] + if (selectTab && selectTab.MenuID === this.props.MenuID) { + this.setShortcut() + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆 + */ + componentWillUnmount () { + this.setState = () => { + return + } + document.onkeydown = () => {} + } + + render() { + const { setting, loadingview, viewlost, config, triggerBtn, userConfig, tabActive, tabgroups, treeNodes, treedata } = this.state + + return ( + <div className="tree-page" id={this.state.ContainerId}> + {loadingview && <Spin size="large" />} + {setting ? <Row gutter={16}> + <Col span={setting.width}> + <Card + className="tree-card" + title={ + <span className="tree-title"> + <span className="title">{setting.title}</span> + {setting.searchable !== 'false' ? <Search onSearch={this.treeFilter} /> : null} + </span> + } + bordered={false} + > + {treeNodes && treeNodes.length > 0 ? <div className="tree-box"> + <Tree + blockNode + onSelect={this.selectTreeNode} + showIcon={setting.showIcon === 'true'} + showLine={setting.showLine === 'true'} + > + {this.renderTreeNodes(treeNodes)} + </Tree> + </div> : null} + {treeNodes && treeNodes.length === 0 ? <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> : null} + {!treedata ? <Spin /> : null} + </Card> + </Col> + <Col span={24 - setting.width} style={{paddingTop: 6}}> + {tabgroups.map(group => ( + <Tabs activeKey={tabActive[group.uuid]} key={group.uuid} onChange={(key) => this.setState({tabActive: {...tabActive, [group.uuid]: key}})}> + {group.sublist.map(_tab => { + return ( + <TabPane tab={ + <span> + {_tab.icon ? <Icon type={_tab.icon} /> : null} + {_tab.label} + </span> + } key={_tab.uuid}> + {_tab.type === 'SubTable' ? + <SubTable + Tab={_tab} + menuType="main" + MenuID={_tab.linkTab} + mainSearch={null} + userConfig={userConfig ? userConfig[_tab.uuid] : null} + triggerBtn={triggerBtn} + SupMenuID={this.props.MenuID} + refreshtabs={this.state.refreshtabs} + ContainerId={this.state.ContainerId} + BID={this.state.BIDs[_tab.supMenu] || ''} + BData={this.state.BIDs[_tab.supMenu + 'data'] || ''} + handleTableId={this.handleTableId} + handleMainTable={(type) => this.handleMainTable(type, _tab)} + /> : null} + </TabPane> + ) + })} + </Tabs>) + )} + </Col> + </Row> : null} + + <Button + icon="copy" + shape="circle" + className="tree-page-copy" + onClick={this.handleviewconfig} + /> + <Modal + className="menu-tree-modal" + title={'鑿滃崟缁撴瀯鏍�'} + width={'650px'} + maskClosable={false} + visible={this.state.treevisible} + onCancel={() => this.setState({treevisible: false})} + footer={[ + <Button key="close" onClick={() => this.setState({treevisible: false})}>{this.state.dict['main.close']}</Button> + ]} + destroyOnClose + > + <div className="menu-header"> + <span>鑿滃崟鍚嶇О锛歿this.props.MenuName}</span> + <span>鑿滃崟鍙傛暟锛歿<Paragraph copyable>{this.props.MenuNo}</Paragraph>}</span> + </div> + {this.state.treevisible ? <Tree defaultExpandAll showLine={true}> + {this.getTreeNode(config.funcs)} + </Tree> : null} + </Modal> + {/* 鎸夐挳浣跨敤绯荤粺瀛樺偍杩囩▼鏃讹紝楠岃瘉淇℃伅妯℃�佹 */} + <Modal + wrapClassName="common-table-custom-modal" + title={'鑷畾涔夎缃�'} + maskClosable={false} + width={950} + visible={this.state.settingVisible} + onCancel={() => { this.setState({ settingVisible: false }) }} + footer={[ + <Button key="revert" type="danger" loading={this.state.revertLoading} onClick={this.settingRevert}>{this.state.dict['main.revert.default']}</Button>, + <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['main.cancel']}</Button>, + <Button key="confirm" type="primary" loading={this.state.confirmLoading} onClick={this.settingSubmit}>{this.state.dict['main.submit']}</Button> + ]} + destroyOnClose + > + {this.state.settingVisible ? + <VerifyCard + MenuID={this.props.MenuID} + MenuName={this.props.MenuName} + permAction={this.props.permAction} + permRoles={this.props.permRoles} + config={this.state.config} + userConfig={this.state.userConfig} + columns={[]} + handleParam={this.changeMenuParam} + /> : null + } + </Modal> + {viewlost ? <NotFount msg={this.state.lostmsg} /> : null} + </div> + ) + } +} + +const mapStateToProps = (state) => { + return { + tabviews: state.tabviews, + refreshTab: state.refreshTab, + permAction: state.permAction, + permMenus: state.permMenus, + permRoles: state.permRoles, + memberLevel: state.memberLevel, + dataManager: state.dataManager + } +} + +const mapDispatchToProps = (dispatch) => { + return { + refreshTabView: (refreshTab) => dispatch(refreshTabView(refreshTab)), + modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TreePage) \ No newline at end of file diff --git a/src/tabviews/treepage/index.scss b/src/tabviews/treepage/index.scss new file mode 100644 index 0000000..c3833fc --- /dev/null +++ b/src/tabviews/treepage/index.scss @@ -0,0 +1,168 @@ +.tree-page { + position: relative; + min-height: calc(100vh - 94px); + padding: 16px 16px 80px; + .box404 { + padding-top: 30px; + } + .ant-modal-mask { + position: absolute; + } + .ant-modal-wrap { + position: absolute; + } + .action-modal .ant-modal { + top: 40px; + max-width: 95%; + .ant-modal-body { + max-height: calc(100vh - 265px); + } + } + > .ant-spin { + position: absolute; + z-index: 10; + left: calc(50% - 22px); + top: calc(50vh - 70px); + } + .tree-card { + min-height: calc(100vh - 125px); + box-shadow: 0px 0px 2px #dddddd; + .ant-card-head { + padding: 0 10px; + .ant-card-head-title { + padding: 13px 0 7px; + .tree-title { + display: inline-block; + width: 100%; + color: #1890ff; + .ant-input-affix-wrapper { + width: calc(100% - 140px); + margin-top: 0px; + float: right; + height: 28px; + + .ant-input { + max-width: 130px; + border-radius: 20px; + height: 30px; + } + .ant-input-suffix { + margin-top: 3px; + } + } + .title { + display: inline-block; + max-width: 50%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } + >.ant-card-body { + padding: 0px; + .ant-menu-inline { + border-right: 0; + margin-top: 2px; + } + + .tree-box { + min-height: calc(100vh - 180px); + overflow-x: auto; + padding-bottom: 20px; + } + .tree-box::-webkit-scrollbar { + height: 10px; + } + .tree-box::-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); + } + .tree-box::-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); + } + .ant-tree-node-selected + .ant-tree.ant-tree-directory > li span.ant-tree-node-content-wrapper::before, + .ant-tree.ant-tree-directory .ant-tree-child-tree > li span.ant-tree-node-content-wrapper::before { + right: 0px; + } + + >.ant-spin { + margin: 10px; + } + } + } + + > .ant-tabs { + padding: 0px 20px; + margin-bottom: 20px; + .ant-tabs-tab:not(.ant-tabs-tab-active) { + cursor: pointer; + } + .ant-tabs-tab.ant-tabs-tab-active { + cursor: default; + } + } + .tree-page-copy { + position: fixed; + z-index: 2; + bottom: 65px; + right: 30px; + width: 40px; + height: 40px; + } + +} + +.menu-tree-modal { + .ant-modal-body { + min-height: 300px; + .menu-header { + text-align: center; + span { + font-weight: 600; + margin-right: 20px; + } + .ant-typography { + font-weight: 600; + display: inline-block; + } + } + .ant-tree li .ant-tree-node-content-wrapper { + cursor: default; + } + } +} +.common-table-custom-modal { + .ant-modal { + top: 50px; + padding-bottom: 5px; + .ant-modal-body { + max-height: calc(100vh - 190px); + min-height: 250px; + 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/tabviews/zshare/cardcomponent/index.jsx b/src/tabviews/zshare/cardcomponent/index.jsx index 7877d82..d17f336 100644 --- a/src/tabviews/zshare/cardcomponent/index.jsx +++ b/src/tabviews/zshare/cardcomponent/index.jsx @@ -295,7 +295,7 @@ {card.details.map((detail, i) => { return ( <div className={detail.class} key={i}> - {this.getContent(detail.column)} + {detail.column ? this.getContent(detail.column) : detail.content} </div> ) })} @@ -538,6 +538,7 @@ </Tabs> : null } {!data || data.length === 0 ? <Empty description={false}/> : null} + <div className="clear"></div> </div> ) } diff --git a/src/tabviews/zshare/cardcomponent/index.scss b/src/tabviews/zshare/cardcomponent/index.scss index 097bebe..75c7e06 100644 --- a/src/tabviews/zshare/cardcomponent/index.scss +++ b/src/tabviews/zshare/cardcomponent/index.scss @@ -1,6 +1,7 @@ .card-row-box { min-height: 50px; padding: 0px 10px; + margin-bottom: 15px; .chart-card-box { padding: 0 10px; @@ -218,4 +219,7 @@ } } } + .clear { + clear: both; + } } diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx index e032fdd..a9f7bb8 100644 --- a/src/templates/comtableconfig/index.jsx +++ b/src/templates/comtableconfig/index.jsx @@ -26,7 +26,6 @@ const { Panel } = Collapse const { confirm } = Modal -const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS const SettingComponent = asyncComponent(() => import('@/templates/sharecomponent/settingcomponent')) const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent')) const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent')) @@ -44,13 +43,12 @@ } state = { - dict: CommonDict, // 瀛楀吀 + dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, config: null, // 椤甸潰閰嶇疆 tableFields: [], // 琛ㄦ牸鏄剧ず鍒� fields: null, // 鎼滅储鏉′欢鍙婃樉绀哄垪锛屽彲閫夊瓧娈� menuformlist: null, // 鍩烘湰淇℃伅琛ㄥ崟瀛楁 formlist: null, // 鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪琛ㄥ崟瀛楁 - card: null, // 缂栬緫鍏冪礌 menuloading: false, // 鑿滃崟淇濆瓨涓� menucloseloading: false, // 鑿滃崟鍏抽棴鏃讹紝閫夋嫨淇濆瓨 loading: false, // 鍔犺浇涓紝椤甸潰spin @@ -254,7 +252,7 @@ } /** - * @description 涓夌骇鑿滃崟鍒囨崲妯℃澘 + * @description 涓夌骇鑿滃崟鍒囨崲妯℃澘(寮冪敤) */ changeTemplate = () => { this.props.handleView({tabview: 'template'}) @@ -1371,7 +1369,7 @@ <div> <EditComponent dict={this.state.dict} type="maintable" config={this.state.config} MenuID={this.props.menu.MenuID} thawButtons={this.state.thawButtons} refresh={this.editConfig}/> <Switch className="big" checkedChildren="鍚�" unCheckedChildren="鍋�" checked={this.state.config.enabled} onChange={this.onEnabledChange} /> - <Button type="primary" onClick={this.changeTemplate}>{this.state.dict['header.menu.template.change']}</Button> + {/* <Button type="primary" onClick={this.changeTemplate}>{this.state.dict['header.menu.template.change']}</Button> */} <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['header.save']}</Button> <Button onClick={this.cancelConfig}>{this.state.dict['header.return']}</Button> </div> @@ -1451,7 +1449,6 @@ </div> {/* 鏍囩缁� */} <TabsComponent - type="main" config={config} tabs={this.state.tabviews} setSubConfig={(item) => this.setSubConfig(item, 'tab')} diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx index 8f9a540..c726398 100644 --- a/src/templates/formtabconfig/index.jsx +++ b/src/templates/formtabconfig/index.jsx @@ -146,6 +146,9 @@ columns = menu.LongParam.columns } + // 閰嶇疆榛樿鍊硷紝鍏煎 + _config.Template = 'FormTab' + this.setState({ config: _config, activeKey: btnTab.activeKey || '0', @@ -2003,7 +2006,6 @@ </div> {/* 鏍囩缁� */} <TabsComponent - type="formtab" config={config} tabs={this.state.tabviews} setSubConfig={(item) => this.setSubConfig(item, 'tab')} diff --git a/src/templates/formtabconfig/source.jsx b/src/templates/formtabconfig/source.jsx index 90bd820..cb82f99 100644 --- a/src/templates/formtabconfig/source.jsx +++ b/src/templates/formtabconfig/source.jsx @@ -6,7 +6,7 @@ class CommonTableBaseData { baseConfig = { - type: 'FormTab', + Template: 'FormTab', enabled: false, setting: { datatype: 'query', diff --git a/src/templates/menuconfig/editthdmenu/index.jsx b/src/templates/menuconfig/editthdmenu/index.jsx index e667b34..bdf7e4c 100644 --- a/src/templates/menuconfig/editthdmenu/index.jsx +++ b/src/templates/menuconfig/editthdmenu/index.jsx @@ -21,6 +21,7 @@ import './index.scss' const ComTableConfig = asyncLoadComponent(() => import('@/templates/comtableconfig')) +const TreePageConfig = asyncLoadComponent(() => import('@/templates/treepageconfig')) const FormTabConfig = asyncLoadComponent(() => import('@/templates/formtabconfig')) const ModalConfig = asyncLoadComponent(() => import('@/templates/modalconfig')) const SubTable = asyncLoadComponent(() => import('@/templates/subtableconfig')) @@ -790,7 +791,7 @@ <TabPane tab="绯荤粺妯℃澘" key="1"> <Row> {this.state.sysTemplates.map((template, index) => { - if (template.hidden) return '' + if (template.hidden) return null return ( <Col key={`${index}`} span={8}> @@ -836,6 +837,14 @@ </div> </div> : null } + {this.state.tabview === 'TreePage' ? + <TreePageConfig + menu={this.state.editMenu} + optionLibs={this.state.optionLibs} + reloadmenu={() => {this.props.reload()}} + handleView={this.handleView} + /> : null + } {this.state.tabview === 'CommonTable' ? <ComTableConfig menu={this.state.editMenu} diff --git a/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx b/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx index 0dd5540..a1f35d5 100644 --- a/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx +++ b/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx @@ -16,7 +16,7 @@ import card1 from '@/assets/img/card1.png' import card2 from '@/assets/img/card2.png' import card3 from '@/assets/img/card3.png' -import card4 from '@/assets/img/card4.png' +// import card4 from '@/assets/img/card4.png' import card5 from '@/assets/img/card5.png' import './index.scss' @@ -125,11 +125,11 @@ url: card3, subelement: ['content', 'avatar', 'header'] }, - { - uuid: 'card4', - url: card4, - subelement: ['content', 'avatar', 'bottom'] - }, + // { + // uuid: 'card4', + // url: card4, + // subelement: ['content', 'avatar', 'bottom'] + // }, { uuid: 'card5', url: card5, diff --git a/src/templates/sharecomponent/tabscomponent/index.jsx b/src/templates/sharecomponent/tabscomponent/index.jsx index 5749ffe..79711ac 100644 --- a/src/templates/sharecomponent/tabscomponent/index.jsx +++ b/src/templates/sharecomponent/tabscomponent/index.jsx @@ -16,7 +16,6 @@ class TablesComponent extends Component { static propTpyes = { - type: PropTypes.string, // 鑿滃崟绫诲瀷 tabs: PropTypes.array, // 鏍囩缁� config: PropTypes.object, // 椤甸潰閰嶇疆 setSubConfig: PropTypes.func, // 瀛愭爣绛鹃厤缃� @@ -28,6 +27,7 @@ tabgroups: [], // 鏍囩缁� card: [], // 缂栬緫鏍囩 group: [], // 缂栬緫缁� + levels: null, // 鏍戝舰椤甸潰鐨勬爣绛剧骇鍒叧鑱� visible: false // 妯℃�佹鎺у埗 } @@ -83,22 +83,28 @@ * @description 鏍囩缂栬緫锛岀瓫閫夊彲閫夌殑涓嬬骇鏍囩涓庡凡鍏宠仈鐨勪笅绾ф爣绛� */ handleTab = (card, _group) => { + const { config } = this.props let tabgroups = fromJS(this.state.tabgroups).toJS() let menus = [ {value: '', text: '绌�'}, - {value: 'mainTable', text: this.props.type === 'main' ? '涓昏〃' : '涓绘暟鎹�'} + {value: 'mainTable', text: '涓昏〃'} ] let equalTabs = [] let supMenu = card.supMenu || '' let equalTab = card.equalTab || [] let isuptab = true let equalTabIds = [] + let levels = {} - tabgroups.forEach((group, i) => { + tabgroups.forEach(group => { if (group.uuid === _group.uuid) { isuptab = false group.sublist.forEach(tab => { // 鍙叧鑱旂殑鍚岀骇鏍囩 + if (tab.level) { + levels[tab.uuid] = tab.level + } + if (tab.uuid === card.uuid) return equalTabIds.push(tab.uuid) @@ -106,6 +112,10 @@ }) } else if (isuptab) { group.sublist.forEach(tab => { + if (tab.level) { + levels[tab.uuid] = tab.level + } + menus.push({ value: tab.uuid, text: tab.label @@ -122,11 +132,16 @@ equalTab = equalTab.filter(tabId => equalTabIds.includes(tabId)) } + if (config.Template !== 'TreePage') { + levels = null + } + this.setState({ visible: true, card: card, + levels: levels, group: _group, - formlist: getTabForm(card, supMenu, menus, equalTab, equalTabs, this.props.type) + formlist: getTabForm(card, supMenu, menus, equalTab, equalTabs, config.Template) }) } @@ -176,6 +191,20 @@ return _group }) + // 鏇存柊涓庝箣鍏宠仈鐨勬爣绛炬樉绀虹骇鍒� + if (config.Template === 'TreePage' && res.level !== card.level) { + tabgroups = tabgroups.map(_group => { + _group.sublist = _group.sublist.map(item => { + if (item.supMenu === res.uuid) { + item.level = res.level + } + + return item + }) + return _group + }) + } + this.setState({ card: null, group: null, @@ -204,6 +233,17 @@ if (_group.uuid === group.uuid) { _group.sublist = _group.sublist.filter(item => item.uuid !== card.uuid) } + return _group + }) + + // 娓呴櫎涓庝箣鍏宠仈鏍囩鐨勪笂绾ф爣绛捐缃� + tabgroups = tabgroups.map(_group => { + _group.sublist = _group.sublist.map(item => { + if (item.supMenu === card.uuid) { + item.supMenu = '' + } + return item + }) return _group }) @@ -386,6 +426,7 @@ dict={this.state.dict} card={this.state.card} tabs={this.props.tabs} + levels={this.state.levels} formlist={this.state.formlist} inputSubmit={this.handleSubmit} wrappedComponentRef={(inst) => this.tabsFormRef = inst} diff --git a/src/templates/sharecomponent/tabscomponent/tabform/index.jsx b/src/templates/sharecomponent/tabscomponent/tabform/index.jsx index eb0bedf..37d686b 100644 --- a/src/templates/sharecomponent/tabscomponent/tabform/index.jsx +++ b/src/templates/sharecomponent/tabscomponent/tabform/index.jsx @@ -1,6 +1,6 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' -import { Form, Row, Col, Input, Select, Icon, Tooltip, Radio } from 'antd' +import { Form, Row, Col, Input, Select, Icon, Tooltip, Radio, InputNumber } from 'antd' import { formRule } from '@/utils/option.js' import Utils from '@/utils/utils.js' import './index.scss' @@ -11,6 +11,7 @@ tabs: PropTypes.array, // 鍙叧鑱旀爣绛鹃泦 dict: PropTypes.object, // 瀛楀吀椤� formlist: PropTypes.any, // 琛ㄥ崟 + levels: PropTypes.any, // 鏍囩鏄剧ず绾у埆 card: PropTypes.object, // 鏍囩椤典俊鎭� inputSubmit: PropTypes.any // 鍥炶溅鎻愪氦浜嬩欢 } @@ -79,20 +80,19 @@ ..._tabs ] item.initVal = '' - item.hidden = true } return item }) }, () => { - this.setState({ - formlist: this.state.formlist.map(item => { - if (item.key === 'linkTab') { - item.hidden = false - } - return item - }) - }) + if (this.props.form.getFieldValue('linkTab') !== undefined) { + this.props.form.setFieldsValue({linkTab: ''}) + } }) + } else if (key === 'supMenu' && this.props.levels) { + + if (value && value !== 'mainTable') { + this.props.form.setFieldsValue({level: this.props.levels[value]}) + } } } @@ -111,7 +111,7 @@ this.state.formlist.forEach((item, index) => { if (item.hidden || item.forbid) return - if (item.type === 'text') { // 鏂囨湰鎼滅储 + if (item.type === 'text') { let rules = [] if (item.key === 'foreignKey') { @@ -143,6 +143,28 @@ ...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, + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + } + ] + })(<InputNumber disabled={item.readonly} min={item.min} max={item.max} precision={0} />)} </Form.Item> </Col> ) @@ -269,7 +291,7 @@ } } return ( - <Form {...formItemLayout} className="ant-advanced-search-form commontable-tab-form"> + <Form {...formItemLayout} className="model-tab-form"> <Row gutter={24}>{this.getFields()}</Row> </Form> ) diff --git a/src/templates/sharecomponent/tabscomponent/tabform/index.scss b/src/templates/sharecomponent/tabscomponent/tabform/index.scss index 930f1a5..d9327f1 100644 --- a/src/templates/sharecomponent/tabscomponent/tabform/index.scss +++ b/src/templates/sharecomponent/tabscomponent/tabform/index.scss @@ -1,7 +1,16 @@ -.ant-advanced-search-form.commontable-tab-form { +.model-tab-form { min-height: 180px; .anticon-question-circle { color: #c49f47; margin-right: 3px; } + .ant-input-number { + width: 100%; + .ant-input-number-input:read-only { + color: red; + :hover { + border-color: #d9d9d9; + } + } + } } \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/index.jsx b/src/templates/sharecomponent/treesettingcomponent/index.jsx new file mode 100644 index 0000000..a45f4f5 --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/index.jsx @@ -0,0 +1,181 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { fromJS } from 'immutable' +import { Icon, Modal, Button, notification } from 'antd' + +import Utils from '@/utils/utils.js' +import zhCN from '@/locales/zh-CN/model.js' +import enUS from '@/locales/en-US/model.js' +import { getTreeSettingForm } from '@/templates/zshare/formconfig' + +import SettingForm from './settingform' +import CreateFunc from '@/templates/zshare/createfunc' +import CreateInterface from '@/templates/zshare/createinterface' + +import './index.scss' + +class TreeSettingComponent extends Component { + static propTpyes = { + MenuID: PropTypes.string, // 鑿滃崟ID + config: PropTypes.object, // 鑿滃崟閰嶇疆淇℃伅 + permFuncField: PropTypes.array, // 瀛樺偍杩囩▼鍙敤寮�澶村瓧娈� + menuformRef: PropTypes.any, // 鑿滃崟鍩烘湰淇℃伅琛ㄥ崟 + updatesetting: PropTypes.func + } + + state = { + dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + menu: null, // 鑿滃崟淇℃伅 + formlist: null, // 琛ㄥ崟淇℃伅 + visible: false, // 妯℃�佹鎺у埗 + loading: false // 璁剧疆淇℃伅楠岃瘉淇濆瓨涓� + } + + /** + * @description 鍏ㄥ眬璁剧疆瑙﹀彂 + */ + changeSetting = () => { + const { menuformRef, MenuID, config, permFuncField } = this.props + let menu = {MenuID: MenuID} + + if (menuformRef) { + menu = {MenuID: MenuID, MenuName: menuformRef.props.form.getFieldValue('MenuName') || '', MenuNo: menuformRef.props.form.getFieldValue('MenuNo') || ''} + } + + let _config = fromJS(config).toJS() + + this.setState({ + visible: true, + formlist: getTreeSettingForm(config.setting, permFuncField, MenuID), + menu: menu, + config: _config + }) + } + + /** + * @description 淇濆瓨椤甸潰閰嶇疆淇℃伅 + */ + settingSave = () => { + const { config } = this.props + + this.setState({ + loading: true + }) + this.settingRef.handleConfirm().then(res => { + this.setState({ + visible: false, + loading: false + }) + this.props.updatesetting({...config, setting: res}) + }, () => { + this.setState({ + loading: false + }) + }) + } + + /** + * @description 鍒涘缓琛ㄦ牸瀛樺偍杩囩▼ + */ + tableCreatFunc = () => { + const { config } = this.props + const { menu } = this.state + + this.settingRef.handleConfirm().then(setting => { + + if (!(setting.interType === 'inner') || !setting.innerFunc) { + notification.warning({ + top: 92, + message: '鎺ュ彛绫诲瀷涓�-鍐呴儴锛屼笖瀛樺湪鍐呴儴鍑芥暟鏃讹紝鎵嶅彲浠ュ垱寤哄瓨鍌ㄨ繃绋嬶紒', + duration: 5 + }) + return + } + + let _config = {...config, setting: setting} + let newLText = Utils.formatOptions(Utils.getTableFunc(setting, menu, _config)) // 鍒涘缓瀛樺偍杩囩▼sql + let DelText = Utils.formatOptions(Utils.dropfunc(setting.innerFunc)) // 鍒犻櫎瀛樺偍杩囩▼sql + + this.refs.funcCreatComponent.exec(setting.innerFunc, newLText, DelText).then(result => { + if (result === 'success') { + this.props.updatesetting(_config) + } + }) + }) + } + + /** + * @description 鍒涘缓琛ㄦ牸鎺ュ彛锛堣鍑猴級 + */ + tableCreatInterface = () => { + const { config } = this.props + const { menu } = this.state + + this.settingRef.handleConfirm().then(setting => { + if (setting.interType !== 'inner' || setting.innerFunc) { + notification.warning({ + top: 92, + message: '鎺ュ彛绫诲瀷涓�-鍐呴儴锛屼笖涓嶅瓨鍦ㄥ唴閮ㄥ嚱鏁版椂锛屾墠鍙互鍒涘缓鎺ュ彛锛�', + duration: 5 + }) + return + } + + let _config = {...config, setting: setting} + let _menu = { + type: 'main', + MenuID: menu.MenuID, + menuName: menu.MenuName, + menuNo: menu.MenuNo + } + + this.refs.tableCreatInterface.triggerOutInterface(_menu, _config) + }) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊 + */ + componentWillUnmount () { + this.setState = () => { + return + } + } + + render() { + const { dict, visible, config } = this.state + + return ( + <div className="model-tree-menu-setting"> + <Icon type="setting" onClick={this.changeSetting} /> + {/* 璁剧疆鍏ㄥ眬閰嶇疆鍙婂垪琛ㄦ暟鎹簮 */} + <Modal + wrapClassName="model-tree-setting-verify-modal" + title={dict['model.edit']} + visible={visible} + width={900} + maskClosable={false} + onCancel={() => { this.setState({ visible: false })}} + footer={[ + <CreateInterface key="interface" dict={dict} ref="tableCreatInterface" trigger={this.tableCreatInterface}/>, + <CreateFunc key="create" dict={dict} ref="funcCreatComponent" trigger={this.tableCreatFunc}/>, + <Button key="cancel" onClick={() => { this.setState({ visible: false }) }}>{this.state.dict['header.cancel']}</Button>, + <Button key="confirm" type="primary" loading={this.state.loading} onClick={this.settingSave}>{this.state.dict['model.confirm']}</Button> + ]} + destroyOnClose + > + <SettingForm + dict={dict} + config={config} + menu={this.state.menu} + inputSubmit={this.settingSave} + formlist={this.state.formlist} + wrappedComponentRef={(inst) => this.settingRef = inst} + /> + </Modal> + </div> + ) + } +} + +export default TreeSettingComponent \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/index.scss b/src/templates/sharecomponent/treesettingcomponent/index.scss new file mode 100644 index 0000000..89b8f64 --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/index.scss @@ -0,0 +1,42 @@ +.model-tree-menu-setting { + > .anticon-setting { + position: absolute; + font-size: 18px; + right: 7px; + top: 5px; + padding: 10px; + z-index: 1; + color: #1890ff; + } +} + +.model-tree-setting-verify-modal { + .ant-modal { + top: 50px; + padding-bottom: 5px; + .ant-modal-body { + max-height: calc(100vh - 190px); + overflow-y: auto; + } + .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); + } + .ant-empty-normal { + margin: 5px 0px; + } + .ant-input-number { + width: 100%; + } + } +} \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.jsx new file mode 100644 index 0000000..1a81170 --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.jsx @@ -0,0 +1,250 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Input, Button, notification, Modal, Select } from 'antd' +import moment from 'moment' + +import Utils from '@/utils/utils.js' +import SettingUtils from '../utils.jsx' +import Api from '@/api' +import './index.scss' + +const { TextArea } = Input + +class CustomForm extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + setting: PropTypes.object, // 璁剧疆 + systemScripts: PropTypes.array, // 绯荤粺鑴氭湰 + scriptsChange: PropTypes.func // 琛ㄥ崟 + } + + state = { + editItem: null, + loading: false, + } + + UNSAFE_componentWillMount() { + + } + + edit = (record) => { + this.setState({ + editItem: record + }) + + this.props.form.setFieldsValue({ + sql: record.sql + }) + } + + handleCancel = () => { + this.setState({ + editItem: null + }) + this.props.form.setFieldsValue({ + sql: '' + }) + } + + handleConfirm = () => { + const { setting } = this.props + + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + 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 _customScript = '' + setting.scripts && setting.scripts.forEach(script => { + if (this.state.editItem && this.state.editItem.uuid === script.uuid) { + _customScript += ` + ${values.sql} + ` + } else if (script.status !== 'false') { + _customScript += ` + ${script.sql} + ` + } + }) + + if (!this.state.editItem) { + _customScript += ` + ${values.sql} + ` + } + + if (_customScript) { + _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg ='' + ${_customScript} + ` + } + + let _setting = {...setting, customScript: _customScript} + + let param = { + func: 's_debug_sql', + LText: SettingUtils.getDebugSql(_setting) + } + + param.LText = Utils.formatOptions(param.LText) + param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + param.secretkey = Utils.encrypt(param.LText, param.timestamp) + + 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 + }) + } + }) + } + }) + } + + 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 formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <Form {...formItemLayout} className="modal-tree-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, orderBy, {setting.valueField}, {setting.labelField}, {setting.parentField} + </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!' + } + ] + })(<TextArea rows={15} />)} + </Form.Item> + </Col> + </Row> + </Form> + ) + } +} + +export default Form.create()(CustomForm) \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.scss b/src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.scss new file mode 100644 index 0000000..d453a92 --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/settingform/customscript/index.scss @@ -0,0 +1,31 @@ +.modal-tree-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; + } + } +} \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx new file mode 100644 index 0000000..c9f9b3f --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx @@ -0,0 +1,765 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { fromJS } from 'immutable' +import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon, notification, InputNumber, Modal, Table, Popconfirm, Typography, Button } from 'antd' +import moment from 'moment' + +import Api from '@/api' +import Utils from '@/utils/utils.js' +import SettingUtils from './utils.jsx' +import CustomScript from './customscript' +import './index.scss' + +const { TextArea } = Input +const { confirm } = Modal +const { Paragraph } = Typography + +class SettingForm extends Component { + static propTpyes = { + type: PropTypes.string, // 鑿滃崟绫诲瀷 + dict: PropTypes.object, // 瀛楀吀椤� + menu: PropTypes.object, // 鑿滃崟淇℃伅 + config: PropTypes.object, // 椤甸潰閰嶇疆淇℃伅 + formlist: PropTypes.array, // 琛ㄥ崟淇℃伅 + inputSubmit: PropTypes.any // 鍥炶溅鎻愪氦浜嬩欢 + } + + state = { + formlist: [], + btnloading: false, + setting: null, + view: 'normal', + systemScripts: [{ + name: '榛樿sql', + value: '' + }], + scriptsColumns: [ + { + title: 'SQL', + dataIndex: 'sql', + width: '70%', + render: (text) => ( + <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph> + ) + }, + { + title: '鐘舵��', + dataIndex: 'status', + width: '10%', + render: (text, record) => record.status === 'false' ? + ( + <div> + {this.props.dict['header.form.status.forbidden']} + <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" /> + </div> + ) : + ( + <div> + {this.props.dict['header.form.status.open']} + <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" /> + </div> + ) + }, + { + title: '鎿嶄綔', + align: 'center', + width: '20%', + dataIndex: 'operation', + render: (text, record) => + (<div> + <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record)} style={{color: '#1890ff'}}><Icon type="edit" /></span> + <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span> + <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span> + <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span> + <Popconfirm + title={this.props.dict['header.form.query.delete']} + okText={this.props.dict['model.confirm']} + cancelText={this.props.dict['header.cancel']} + onConfirm={() => this.handleDelete(record) + }> + <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span> + </Popconfirm> + </div>) + } + ] + } + + UNSAFE_componentWillMount() { + let _formlist = fromJS(this.props.formlist).toJS() + let interType = 'inner' + + _formlist.forEach(item => { + if (item.key === 'interType') { + interType = item.initVal + } + }) + + let _setting = fromJS(this.props.config.setting).toJS() + _setting.scripts = _setting.scripts || [] + _setting.default = _setting.default || 'true' + + this.setState({ + setting: _setting, + formlist: _formlist.map(item => { + if (interType === 'inner' && ['sysInterface', 'interface', 'outerFunc'].includes(item.key)) { + item.hidden = true + } else if (interType === 'outer' && ['innerFunc', 'dataresource', 'queryType'].includes(item.key)) { + item.hidden = true + } + + return item + }) + }) + } + + componentDidMount () { + this.getsysScript() + } + + getsysScript = () => { + let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from聽 s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort` + + _scriptSql = Utils.formatOptions(_scriptSql) + + let _sParam = { + func: 'sPC_Get_SelectedList', + LText: _scriptSql, + obj_name: 'data', + arr_field: 'funcname,longparam' + } + + _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp) + + Api.getSystemConfig(_sParam).then(res => { + if (res.status) { + let _scripts = res.data.map(item => { + let _item = { + name: item.funcname, + value: Utils.formatOptions(item.longparam, true) + } + + return _item + }) + + this.setState({ + systemScripts: [...this.state.systemScripts, ..._scripts] + }) + } else { + notification.warning({ + top: 92, + message: res.message, + duration: 5 + }) + } + }) + } + + handleConfirm = (otype) => { + const { menu } = this.props + const { view, setting } = this.state + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + + if (view !== 'custom') { + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + values = {...setting, ...values} + + // 鏁版嵁婧愬墠绔獙璇� + if (values.interType === 'inner' && !values.innerFunc && values.default !== 'false' && !values.dataresource) { + notification.warning({ + top: 92, + message: '璇峰~鍐欏唴閮ㄥ嚱鏁版垨鏁版嵁婧愶紒', + duration: 5 + }) + reject() + return + } else if (values.interType === 'inner' && !values.innerFunc && values.default !== 'false' && values.dataresource) { + let error = Utils.verifySql(values.dataresource) + + if (error) { + notification.warning({ + top: 92, + message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error, + duration: 5 + }) + reject() + return + } + } + + // 鏁版嵁婧愪繚瀛� + if ( + values.interType === 'inner' && !values.innerFunc && + values.default !== 'false' && + /[^\s]+\s+[^\s]+/ig.test(values.dataresource) && + this.props.config.setting.dataresource !== values.dataresource + ) { + let param = { + func: 's_DataSrc_Save', + LText: values.dataresource, + MenuID: menu.MenuID + } + + param.LText = Utils.formatOptions(param.LText) + param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + param.secretkey = Utils.encrypt(param.LText, param.timestamp) + + Api.getLocalConfig(param) + } + + if (otype === 'change') { + this.setState({ + setting: values, + }, () => { + resolve() + }) + } else { + values.customScript = this.getCustomScript(values) + + this.sqlverify(values, resolve, reject) + } + } else { + reject(err) + } + }) + }) + } else { + let _setting = fromJS(this.state.setting).toJS() + _setting.customScript = this.getCustomScript(_setting) + + let _this = this + + return new Promise((resolve, reject) => { + if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) { + confirm({ + content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氭彁浜ゅ悧锛焋, + okText: this.props.dict['model.confirm'], + cancelText: this.props.dict['header.cancel'], + onOk() { + _this.sqlverify(_setting, resolve, reject) + }, + onCancel() { + reject() + } + }) + } else { + this.sqlverify(_setting, resolve, reject) + } + }) + } + } + + getCustomScript = (setting) => { + let _customScript = '' + if (setting.scripts && setting.scripts.length > 0) { + setting.scripts.forEach(item => { + if (item.status === 'false') return + _customScript += ` + ${item.sql} + ` + }) + } + + if (_customScript) { + _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg ='' + ${_customScript} + ` + } + + return _customScript + } + + sqlverify = (_setting, _resolve, _reject, isChange = false) => { + if (!isChange && _setting.interType === 'inner' && !_setting.innerFunc && _setting.default === 'false' && !_setting.customScript) { + notification.warning({ + top: 92, + message: '涓嶆墽琛岄粯璁ql鏃讹紝璇锋坊鍔犺嚜瀹氫箟鑴氭湰锛�', + duration: 5 + }) + _reject() + return + } + + if (_setting.interType === 'inner' && !_setting.innerFunc && _setting.default !== 'false') { + let param = { + func: 's_debug_sql', + LText: SettingUtils.getDebugSql(_setting) + } + param.LText = Utils.formatOptions(param.LText) + param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + param.secretkey = Utils.encrypt(param.LText, param.timestamp) + + Api.getLocalConfig(param).then(result => { + if (result.status) { + _resolve(_setting) + } else { + _reject() + Modal.error({ + title: result.message + }) + } + }) + } else { + _resolve(_setting) + } + } + + selectChange = (key, val) => { + if (key === 'primaryKey' && val) { + this.props.form.setFieldsValue({ + order: `${val} desc` + }) + } + } + + onRadioChange = (e, key) => { + let value = e.target.value + let _formlist = fromJS(this.state.formlist).toJS() + + if (key === 'interType') { + this.setState({ + formlist: _formlist.map(item => { + item.hidden = false + + if (value === 'inner' && ['sysInterface', 'interface', 'outerFunc'].includes(item.key)) { + item.initVal = this.props.form.getFieldValue(item.key) + item.hidden = true + } else if (value === 'outer' && ['innerFunc', 'dataresource', 'queryType'].includes(item.key)) { + item.initVal = this.props.form.getFieldValue(item.key) + item.hidden = true + } + + return item + }) + }) + } else if (key === 'sysInterface') { + if (value === 'true') { + this.props.form.setFieldsValue({ + interface: window.GLOB.mainSystemApi || '' + }) + } + this.setState({ + formlist: _formlist.map(item => { + if (item.key === 'interface') { + item.readonly = value === 'true' + } + + return item + }) + }) + } + } + + changeView = () => { + const { view } = this.state + let _this = this + + if (view === 'normal') { + this.handleConfirm('change').then(() => { + const { setting } = this.state + + if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) { + notification.warning({ + top: 92, + message: '浣跨敤澶栭儴鎺ュ彛鎴栧唴閮ㄦ帴鍙g殑鑷畾涔夊嚱鏁帮紝涓嶅彲娣诲姞鑷畾涔夎缃紒', + duration: 5 + }) + return + } + + let _dataresource = setting.dataresource + + if (/\s/.test(_dataresource)) { + _dataresource = '(' + _dataresource + ') tb' + } + + let arr_field = `${setting.valueField}, ${setting.labelField}, ${setting.parentField}` + + let LText = `select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource}) tmptable order by tmptable.rows` + let _scripts = fromJS(this.state.systemScripts).toJS() + _scripts[0].value = LText + + + if (setting.default === 'false') { + this.setState({ + view: 'custom', + btnloading: false, + systemScripts: _scripts + }) + this.scrolltop() + } else { + this.setState({ + btnloading: true + }) + new Promise((resolve, reject) => { + this.sqlverify(setting, resolve, reject, true) + }).then(() => { + this.setState({ + view: 'custom', + btnloading: false, + systemScripts: _scripts + }) + this.scrolltop() + }, () => { + this.setState({ + btnloading: false + }) + }) + } + }) + } else { + let _loading = false + + if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) { + _loading = true + } + + if (_loading) { + confirm({ + content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氬垏鎹㈠悧锛焋, + okText: this.props.dict['model.confirm'], + cancelText: this.props.dict['header.cancel'], + onOk() { + _this.setState({ + view: 'normal' + }) + + _this.scrolltop() + }, + onCancel() {} + }) + } else { + _this.setState({ + view: 'normal' + }) + + _this.scrolltop() + } + } + } + + handleSubmit = (e) => { + e.preventDefault() + + if (this.props.inputSubmit) { + this.props.inputSubmit() + } + } + + getFields(formlist) { + const { getFieldDecorator } = this.props.form + const fields = [] + + formlist.forEach((item, index) => { + if (item.hidden || item.forbid) return + + if (item.type === 'text') { // 鏂囨湰鎼滅储 + let rules = item.rules || [] + + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.tooltip ? + <Tooltip placement={item.placement || 'topLeft'} title={item.tooltip}> + <Icon type="question-circle" /> + {item.label} + </Tooltip> : item.label + }> + {getFieldDecorator(item.key, { + initialValue: item.initVal || '', + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + }, + ...rules + ] + })(<Input placeholder={item.placeholder || ''} autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'number') { + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.tooltip ? + <Tooltip placement="topLeft" title={item.tooltip}> + <Icon type="question-circle" /> + {item.label} + </Tooltip> : item.label + }> + {getFieldDecorator(item.key, { + initialValue: item.initVal || 6, + rules: [ + { + required: item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + } + ] + })(<InputNumber min={item.min} max={item.max} precision={0} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'select') { // 涓嬫媺鎼滅储 + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.label}> + {getFieldDecorator(item.key, { + initialValue: item.initVal || '', + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.select'] + item.label + '!' + } + ] + })( + <Select + showSearch + filterOption={(input, option) => { + return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 || + option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0 + }} + onChange={(value) => {this.selectChange(item.key, value)}} + getPopupContainer={() => document.getElementById('model-table-setting-form')} + > + {item.options.map((option, i) => + <Select.Option id={i} key={i} value={option.value}> + {option.text} + </Select.Option> + )} + </Select> + )} + </Form.Item> + </Col> + ) + } else if (item.type === 'radio') { + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.tooltip ? + <Tooltip placement="topLeft" title={item.tooltip}> + <Icon type="question-circle" /> + {item.label} + </Tooltip> : item.label + }> + {getFieldDecorator(item.key, { + initialValue: item.initVal, + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.select'] + item.label + '!' + } + ] + })( + <Radio.Group onChange={(e) => {this.onRadioChange(e, item.key)}}> + { + item.options.map((option, i) => { + return ( + <Radio key={i} value={option.value}>{option.text}</Radio> + ) + }) + } + </Radio.Group>, + )} + </Form.Item> + </Col> + ) + } else if (item.type === 'datasource') { + fields.push( + <Col span={24} key={index} style={{paddingLeft: '7px'}}> + <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } help={item.help} label={ + <Tooltip placement="topLeft" title={item.tooltip}> + <Icon type="question-circle" /> + {item.label} + </Tooltip> + }> + {getFieldDecorator(item.key, { + initialValue: item.initVal + })(<TextArea rows={4} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'textarea') { + fields.push( + <Col span={20} offset={4} key={index}> + <Form.Item className="text-area"> + {getFieldDecorator(item.key, { + initialValue: item.initVal, + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + } + ] + })(<TextArea rows={4} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'multiselect') { // 澶氶�� + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.label}> + {getFieldDecorator(item.key, { + initialValue: item.initVal || [] + })( + <Select + showSearch + mode="multiple" + filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} + > + {item.options.map((option, i) => + <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option> + )} + </Select> + )} + </Form.Item> + </Col> + ) + } + }) + + return fields + } + + handleEdit = (record) => { + this.scriptsForm.edit(record) + + this.scrolltop() + } + + scrolltop = () => { + let node = document.getElementById('model-tree-setting-form-box').parentNode + + if (node && node.scrollTop) { + let inter = Math.ceil(node.scrollTop / 10) + + let timer = setInterval(() => { + if (node.scrollTop - inter > 0) { + node.scrollTop = node.scrollTop - inter + } else { + node.scrollTop = 0 + clearInterval(timer) + } + }, 10) + } + } + + handleUpDown = (record, direction) => { + let scripts = fromJS(this.state.setting.scripts).toJS() + let index = 0 + + scripts = scripts.filter((item, i) => { + if (item.uuid === record.uuid) { + index = i + } + + return item.uuid !== record.uuid + }) + if ((index === 0 && direction === 'up') || (index === scripts.length && direction === 'down')) { + return + } + + if (direction === 'up') { + scripts.splice(index - 1, 0, record) + } else { + scripts.splice(index + 1, 0, record) + } + + this.setState({ + setting: {...this.state.setting, scripts: scripts} + }) + } + + handleStatus = (record) => { + let scripts = fromJS(this.state.setting.scripts).toJS() + record.status = record.status === 'false' ? 'true' : 'false' + + scripts = scripts.map(item => { + if (item.uuid === record.uuid) { + return record + } else { + return item + } + }) + + this.setState({ + setting: {...this.state.setting, scripts: scripts} + }) + } + + handleDelete = (record) => { + let scripts = fromJS(this.state.setting.scripts).toJS() + scripts = scripts.filter(item => item.uuid !== record.uuid) + + this.setState({ setting: {...this.state.setting, scripts: scripts} }) + } + + scriptsChange = (values) => { + let scripts = fromJS(this.state.setting.scripts).toJS() + + if (values.uuid) { + scripts = scripts.map(item => { + if (item.uuid === values.uuid) { + return values + } else { + return item + } + }) + } else { + values.uuid = Utils.getuuid() + scripts.push(values) + } + + this.setState({ + setting: {...this.state.setting, scripts: scripts} + }) + } + + render() { + const { config, type } = this.props + const { formlist, view, setting, scriptsColumns, systemScripts, btnloading } = this.state + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + + return ( + <div className="model-tree-setting-form-box" id="model-tree-setting-form-box"> + {view ==='custom' ? <div> + <Icon className="setting-custom-back" onClick={this.changeView} type="arrow-left" /> + <CustomScript + type={type} + setting={setting} + dict={this.props.dict} + searches={config.search} + systemScripts={systemScripts} + scriptsChange={this.scriptsChange} + wrappedComponentRef={(inst) => this.scriptsForm = inst} + /> + <Table + bordered + rowKey="uuid" + className="custom-table" + dataSource={setting.scripts} + columns={scriptsColumns} + pagination={false} + /> + </div> : null } + <Form {...formItemLayout} className="model-tree-setting-form" id="model-table-setting-form"> + {view !=='custom' ? <Row gutter={24}>{this.getFields(formlist)}</Row> : null} + <Row gutter={24}> + {view !=='custom' ? <Button onClick={this.changeView} className="to-custom-script" loading={btnloading}>鑷畾涔夎缃�<Icon style={{marginLeft: 5}} type="right" /></Button> : null} + {view ==='custom' ? <span onClick={this.changeView} style={{float: 'left', color: '#1890ff', marginLeft: 12, marginTop: 15, cursor: 'pointer'}}><Icon style={{marginRight: 5}} type="left" />鍩虹璁剧疆</span> : null} + </Row> + </Form> + </div> + ) + } +} + +export default Form.create()(SettingForm) \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/index.scss b/src/templates/sharecomponent/treesettingcomponent/settingform/index.scss new file mode 100644 index 0000000..aa3e0b8 --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/settingform/index.scss @@ -0,0 +1,45 @@ +.model-tree-setting-form-box { + position: relative; + .model-tree-setting-form { + .textarea { + .ant-form-item-label { + width: 16.3%; + } + .ant-form-item-control-wrapper { + width: 83.33333333%; + } + } + .anticon-question-circle { + color: #c49f47; + margin-right: 3px; + } + } + .operation-btn { + display: inline-block; + font-size: 16px; + padding: 0 5px; + cursor: pointer; + } + td { + word-break: break-all; + } + .setting-custom-back { + position: absolute; + top: -20px; + left: -10px; + font-size: 16px; + z-index: 1; + cursor: pointer; + padding: 10px; + color: rgb(24, 144, 255); + } + .to-custom-script { + float: right; + color: #1890ff; + margin-right: 12px; + margin-top: 15px; + cursor: pointer; + border: 0; + box-shadow: unset; + } +} \ No newline at end of file diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx new file mode 100644 index 0000000..ae1a6b6 --- /dev/null +++ b/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx @@ -0,0 +1,51 @@ + +export default class SettingUtils { + /** + * @description 鐢熸垚椤甸潰鏌ヨ璇彞 + * @return {Object} setting 椤甸潰璁剧疆 + */ + static getDebugSql (setting) { + 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, '') + } + + if (_customScript) { + _customScript = _customScript.replace(/@orderBy@/ig, setting.order) + } + + // 鏁版嵁婧愬鐞� + if (_dataresource) { + if (/\s/.test(_dataresource)) { + _dataresource = '(' + _dataresource + ') tb' + } + + let arr_field = `${setting.valueField}, ${setting.labelField}, ${setting.parentField}` + + _dataresource = `select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource}) tmptable 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/templates/subtableconfig/index.jsx b/src/templates/subtableconfig/index.jsx index 991316a..217740f 100644 --- a/src/templates/subtableconfig/index.jsx +++ b/src/templates/subtableconfig/index.jsx @@ -33,7 +33,7 @@ const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent')) const ChartGroupComponent = asyncComponent(() => import('@/templates/sharecomponent/chartgroupcomponent')) const ChartComponent = asyncComponent(() => import('@/templates/sharecomponent/chartcomponent')) -// const CardComponent = asyncComponent(() => import('@/templates/sharecomponent/cardcomponent')) +const CardComponent = asyncComponent(() => import('@/templates/sharecomponent/cardcomponent')) class SubTableConfig extends Component { static propTpyes = { @@ -1169,6 +1169,16 @@ /> </Col> ) + } else if (item.chartType === 'card') { + return ( + <Col span={item.width} key={item.uuid}> + <CardComponent + card={item} + config={config} + plotchange={this.updateconfig} + /> + </Col> + ) } else { return ( <Col span={item.width} key={item.uuid}> diff --git a/src/templates/treepageconfig/index.jsx b/src/templates/treepageconfig/index.jsx new file mode 100644 index 0000000..61dd4a9 --- /dev/null +++ b/src/templates/treepageconfig/index.jsx @@ -0,0 +1,921 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { is, fromJS } from 'immutable' +import { DndProvider } from 'react-dnd' +import HTML5Backend from 'react-dnd-html5-backend' +import { Button, Card, Modal, Collapse, notification, Spin, Icon, Switch, Tooltip, Row, Col, Tree } 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 { getMainMenuForm } from '@/templates/zshare/formconfig' + +import asyncComponent from '@/utils/asyncComponent' + +import MenuForm from '@/templates/zshare/menuform' +import EditComponent from '@/templates/zshare/editcomponent' +import SourceElement from '@/templates/zshare/dragsource' +import Source from './source' +import './index.scss' + +const { Panel } = Collapse +const { confirm } = Modal +const { TreeNode } = Tree +const TreeSettingComponent = asyncComponent(() => import('@/templates/sharecomponent/treesettingcomponent')) +const TabsComponent = asyncComponent(() => import('@/templates/sharecomponent/tabscomponent')) + +class ComTableConfig extends Component { + static propTpyes = { + menu: PropTypes.any, + optionLibs: PropTypes.any, + reloadmenu: PropTypes.func, + handleView: PropTypes.func + } + + state = { + dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + config: null, // 椤甸潰閰嶇疆 + menuformlist: null, // 鍩烘湰淇℃伅琛ㄥ崟瀛楁 + formlist: null, // 鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪琛ㄥ崟瀛楁 + menuloading: false, // 鑿滃崟淇濆瓨涓� + menucloseloading: false, // 鑿滃崟鍏抽棴鏃讹紝閫夋嫨淇濆瓨 + loading: false, // 鍔犺浇涓紝椤甸潰spin + closeVisible: false, // 鍏抽棴妯℃�佹 + tables: [], // 鍙敤琛ㄥ悕 + originMenu: null, // 鍘熷鑿滃崟 + delTabs: [], // 鍒犻櫎鏍囩鍒楄〃 + tabviews: [], // 鎵�鏈夋爣绛鹃〉 + optionLibs: null, // 鑷畾涔変笅鎷夐�夐」搴� + activeKey: '0', // 榛樿灞曞紑鍩烘湰淇℃伅 + pasteContent: null, // 绮樿创閰嶇疆淇℃伅 + openEdition: '' // 缂栬緫鐗堟湰鏍囪锛岄槻姝㈠浜烘搷浣� + } + + /** + * @description 鏁版嵁棰勫鐞� + * 1銆佽缃〉闈㈤厤缃俊鎭紝鏂板缓鎴栨棤閰嶇疆淇℃伅鏃讹紙鍒囨崲妯℃澘鍚庢棤閰嶇疆淇℃伅锛夛紝浣跨敤妯℃澘榛樿閰嶇疆 + * 2銆佽缃搷浣滅被鍨嬨�佸師濮嬭彍鍗曚俊鎭紙姣忔淇濆瓨鍚庨噸缃級銆佸凡浣跨敤琛ㄥ強鍩烘湰淇℃伅琛ㄥ崟 + */ + UNSAFE_componentWillMount () { + const { menu, optionLibs } = this.props + + let _LongParam = menu.LongParam + let _config = '' + + if (!_LongParam) { + _config = fromJS(Source.baseConfig).toJS() + _config.isAdd = true + } else { + _config = _LongParam + } + + // 閰嶇疆榛樿鍊硷紝鍏煎 + _config.Template = 'TreePage' + _config.easyCode = _config.easyCode || '' + + if (_config.type === 'user') { + // 閲嶇疆鏍囩ID + _config.tabgroups.forEach(group => { + group.sublist = group.sublist.map(tab => { + tab.uuid = Utils.getuuid() + + if (tab.linkTab) { + tab.linkTab = '' + } + + return tab + }) + }) + } + + this.setState({ + config: _config, + openEdition: menu.open_edition || '', + activeKey: menu.activeKey || '0', + optionLibs: optionLibs, + originMenu: fromJS(menu).toJS(), + menuformlist: getMainMenuForm(menu, _config) + }) + } + + /** + * @description 鍔犺浇瀹屾垚鍚�, 鑾峰彇鎵�鏈夋爣绛鹃〉淇℃伅 + */ + componentDidMount () { + this.reloadTab(false) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊 + */ + componentWillUnmount () { + this.setState = () => { + return + } + } + + /** + * @description 鍔犺浇鎴栧埛鏂版爣绛句俊鎭� + */ + reloadTab = (type) => { + this.setState({ + loading: type, + tabviews: [] + }) + Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'tab'}).then(res => { + if (res.status) { + this.setState({ + loading: false, + tabviews: res.UserTemp.map(temp => { + return { + uuid: temp.MenuID, + value: temp.MenuID, + text: temp.MenuName, + type: temp.Template, + MenuNo: temp.MenuNo + } + }) + }) + + if (type) { + notification.success({ + top: 92, + message: '鍒锋柊鎴愬姛銆�', + duration: 2 + }) + } + } else { + this.setState({ + loading: false + }) + notification.warning({ + top: 92, + message: res.message, + duration: 5 + }) + } + }) + } + + getFuncNames = (data, funcNames, tableNames) => { + data.forEach(item => { + if (item.subfuncs) { + this.getFuncNames(item.subfuncs, funcNames, tableNames) + } else { + if (item.tableName) { + tableNames.push(item.tableName) + } + if (item.innerFunc) { + funcNames.push({func: item.innerFunc, label: item.label || ''}) + } + + if (item.callbackFunc) { + funcNames.push({func: item.callbackFunc, label: item.label || ''}) + } + } + }) + + return { + func: funcNames, + table: tableNames + } + } + + /** + * @description 涓夌骇鑿滃崟淇濆瓨 + */ + submitConfig = () => { + const { menu } = this.props + const { originMenu, delTabs, openEdition } = this.state + + let config = fromJS(this.state.config).toJS() + + this.menuformRef.handleConfirm().then(res => { + if (config.isAdd) { + config.tabgroups[0].sublist = config.tabgroups[0].sublist.filter(item => !item.origin) + } + + if (config.type === 'user') { // 浣跨敤宸叉湁鑿滃崟鏃讹紝榛樿娣诲姞鍏宠仈鏍囩id + config.tabgroups.forEach(group => { + group.sublist = group.sublist.map(tab => { + if (!tab.linkTab) { + tab.linkTab = Utils.getuuid() + } + return tab + }) + }) + } + + let _LongParam = '' + let _config = {...config, easyCode: res.easyCode} + let _pageParam = {...menu.PageParam, OpenType: res.opentype} + + // 鏈缃暟鎹簮鎴栨爣绛句笉鍚堟硶鏃讹紝鍚敤鐘舵�佷负false + let vresult = this.verifyconfig(_config) + if (vresult !== true) { + _config.enabled = false + } + + _config.funcs = [] // 椤甸潰鍙婂瓙椤甸潰瀛樺偍杩囩▼闆� + + _config.funcs.push({ + type: 'view', + subtype: 'view', + uuid: menu.MenuID, + intertype: _config.setting.interType || 'inner', + interface: _config.setting.interface || '', + tableName: _config.setting.tableName || '', + innerFunc: _config.setting.innerFunc || '', + outerFunc: _config.setting.outerFunc || '' + }) + + _config.tabgroups.forEach(group => { + group.sublist.forEach(tab => { + _config.funcs.push({ + type: 'tab', + subtype: 'tab', + uuid: tab.uuid, + label: tab.label, + linkTab: tab.linkTab + }) + }) + }) + + if (this.state.closeVisible) { // 鏄剧ず鍏抽棴瀵硅瘽妗嗘椂锛屾ā鎬佹涓繚瀛樻寜閽紝鏄剧ず淇濆瓨涓姸鎬� + this.setState({ + menucloseloading: true + }) + } else { + this.setState({ + menuloading: true + }) + } + + new Promise(resolve => { + let deffers = [] + _config.funcs.forEach(item => { + if (item.type === 'tab') { + let deffer = new Promise(resolve => { + Api.getSystemConfig({ + func: 'sPC_Get_LongParam', + MenuID: item.linkTab + }).then(result => { + if (result.status && result.LongParam) { + let _LongParam = '' + + if (result.LongParam) { + try { + _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) + } catch (e) { + console.warn('Parse Failure') + _LongParam = '' + } + } + + if (_LongParam) { + item.menuNo = _LongParam.tabNo || '' + item.subfuncs = _LongParam.funcs || [] + } + } + resolve() + }) + }) + + deffers.push(deffer) + } + }) + + if (deffers.length === 0) { + resolve() + } else { + Promise.all(deffers).then(() => { + resolve() + }) + } + }).then(() => { + // 淇濆瓨鏃跺垹闄ら厤缃被鍨嬶紝system 銆乽ser + delete _config.type + delete _config.isAdd + + try { + _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config))) + } catch (e) { + notification.warning({ + top: 92, + message: '缂栬瘧閿欒', + duration: 5 + }) + this.setState({ + menucloseloading: false, + menuloading: false + }) + return + } + + let _sort = 0 + let btntabs = [] + + let tabParam = { // 娣诲姞鑿滃崟tab椤� + func: 'sPC_sMenusTab_AddUpt', + MenuID: menu.MenuID + } + + let _LText = [] + + btntabs.forEach(item => { + _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`) + }) + _config.tabgroups.forEach(group => { + group.sublist.forEach(item => { + _sort++ + _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`) + }) + }) + + _LText = _LText.join(' union all ') + + tabParam.LText = Utils.formatOptions(_LText) + tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp) + + let _vals = this.getFuncNames(_config.funcs, [], []) + let _tables = Array.from(new Set(_vals.table)) + + let param = { + func: 'sPC_TrdMenu_AddUpt', + FstID: res.fstMenuId, + SndID: res.parentId, + ParentID: res.parentId, + MenuID: menu.MenuID, + MenuNo: res.MenuNo, + EasyCode: res.easyCode, + Template: menu.PageParam.Template || '', + MenuName: res.MenuName, + PageParam: JSON.stringify(_pageParam), + LongParam: _LongParam, + LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`), + LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`) + } + + if (menu.menuSort) { // 鑿滃崟鏂板缓鏃惰缃帓搴� + param.Sort = menu.menuSort + } + + param.LText = param.LText.join(' union all ') + param.LText = Utils.formatOptions(param.LText) + param.LTexttb = param.LTexttb.join(' union all ') + param.LTexttb = Utils.formatOptions(param.LTexttb) + param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' + param.secretkey = Utils.encrypt(param.LText, param.timestamp) + + if (openEdition) { // 鐗堟湰绠$悊 + param.open_edition = openEdition + } + + // 鏈夋寜閽垨鏍囩鍒犻櫎鏃讹紝鍏堣繘琛屽垹闄ゆ搷浣� + // 鍒犻櫎鎴愬姛鍚庯紝淇濆瓨椤甸潰閰嶇疆 + new Promise(resolve => { + if (delTabs.length > 0) { + let deffers = delTabs.map(item => { + let _param = { + func: 'sPC_MainMenu_Del', + MenuID: item.uuid + } + + return new Promise(resolve => { + Api.getSystemConfig(_param).then(response => { + resolve(response) + }) + }) + }) + Promise.all(deffers).then(result => { + let error = null + result.forEach(response => { + if (!response.status) { + error = response + } + }) + + if (error) { + this.setState({ + menuloading: false, + menucloseloading: false + }) + notification.warning({ + top: 92, + message: error.message, + duration: 5 + }) + resolve(false) + } else { + this.setState({ + delTabs: [] + }) + resolve(true) + } + }) + } else if (delTabs.length === 0) { + resolve(true) + } + }).then(resp => { + if (resp === false) return + let localParam = fromJS(param).toJS() + + Api.getSystemConfig(param).then(response => { + if (response.status) { + let _FMenu = originMenu.fstMenuList.filter(fstM => fstM.MenuID === res.fstMenuId)[0] + let _supMenuList = [] + if (_FMenu) { + _supMenuList = _FMenu.options + } + + this.setState({ + config: _config, + openEdition: response.open_edition || '', + originMenu: { + ...originMenu, + LongParam: _config, + PageParam: _pageParam, + MenuName: res.MenuName, + MenuNo: res.MenuNo, + ParentID: res.parentId, + fstMenuId: res.fstMenuId, + supMenuList: _supMenuList + } + }) + + this.props.reloadmenu() + + // 瀛樺湪鏍囩椤垫椂 + if (tabParam.LText) { + Api.getSystemConfig(tabParam).then(result => { + if (result.status) { + notification.success({ + top: 92, + message: '淇濆瓨鎴愬姛', + duration: 2 + }) + if (this.state.closeVisible) { + this.props.handleView() + } else { + this.setState({ + menuloading: false, + menucloseloading: false + }) + } + } else { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + this.setState({ + menuloading: false, + menucloseloading: false + }) + } + }) + } else { + notification.success({ + top: 92, + message: '淇濆瓨鎴愬姛', + duration: 2 + }) + if (this.state.closeVisible) { + this.props.handleView() + } else { + this.setState({ + menuloading: false, + menucloseloading: false + }) + } + } + + localParam.func = 'sPC_TrdMenu_AddUpt_For_Local' + delete localParam.LongParam + delete localParam.PageParam + delete localParam.Template + delete localParam.Sort + delete localParam.EasyCode + delete localParam.open_edition + + Api.getLocalConfig(localParam) + } else { + this.setState({ + menuloading: false, + menucloseloading: false + }) + notification.warning({ + top: 92, + message: response.message, + duration: 5 + }) + } + }) + }) + }) + }, () => { + notification.warning({ + top: 92, + message: this.state.dict['header.menu.basemsg'], + duration: 5 + }) + }) + } + + /** + * @description 鐐瑰嚮杩斿洖鏃讹紝鍒ゆ柇閰嶇疆淇濆瓨鐘舵�� + */ + cancelConfig = () => { + const { menu } = this.props + const { config, originMenu } = this.state + + let _this = this + + if (config.isAdd) { + confirm({ + content: '鑿滃崟灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�', + okText: this.state.dict['model.confirm'], + cancelText: this.state.dict['header.cancel'], + onOk() { + _this.props.handleView() + }, + onCancel() {} + }) + } else { + this.menuformRef.handleConfirm().then(res => { + let _config = {...config, easyCode: res.easyCode} + let _pageParam = {...menu.PageParam, OpenType: res.opentype} + let _originMenu = { + ...originMenu, + LongParam: _config, + PageParam: _pageParam, + MenuName: res.MenuName, + MenuNo: res.MenuNo, + ParentID: res.parentId, + fstMenuId: res.fstMenuId + } + + if (!is(fromJS(originMenu), fromJS(_originMenu))) { + this.setState({ + closeVisible: true + }) + } else { + this.props.handleView() + } + }, () => { + this.setState({ + closeVisible: true + }) + }) + } + } + + /** + * @description 璁剧疆鍙厤缃寜閽� + */ + setSubConfig = (item, type) => { + const { menu } = this.props + const { config, originMenu, optionLibs, activeKey, openEdition } = this.state + + if (!originMenu.MenuID) { // menuID涓嶅瓨鍦ㄦ椂锛屼负鏂板缓鑿滃崟锛屾彁绀鸿彍鍗曞皻鏈繚瀛� + notification.warning({ + top: 92, + message: this.state.dict['header.menu.config.notsave'], + duration: 5 + }) + } else { + this.menuformRef.handleConfirm().then(res => { + let _config = {...config, easyCode: res.easyCode} + let _pageParam = {...menu.PageParam, OpenType: res.opentype} + let _originMenu = { + ...originMenu, + LongParam: _config, + PageParam: _pageParam, + MenuName: res.MenuName, + MenuNo: res.MenuNo, + ParentID: res.parentId, + fstMenuId: res.fstMenuId + } + + if (!is(fromJS(originMenu), fromJS(_originMenu))) { // 鑿滃崟淇℃伅鍙樺寲鏃讹紝鎻愮ず淇濆瓨 + notification.warning({ + top: 92, + message: this.state.dict['header.menu.config.update'], + duration: 5 + }) + return + } + + _originMenu.activeKey = activeKey // 淇濆瓨褰撳墠鎵撳紑椤电 + _originMenu.open_edition = openEdition // 鏇存柊鐗堟湰鍙� + + let param = { + optionLibs: optionLibs, + editMenu: _originMenu, + editTab: item, + tabConfig: null, + editSubTab: null, + subTabConfig: null, + btnTab: null, + btnTabConfig: null, + editAction: null, + subConfig: '', + tabview: item.type + } + + this.setState({ + loading: true + }) + + Api.getSystemConfig({ + func: 'sPC_Get_LongParam', + MenuID: item.linkTab + }).then(res => { + if (res.status) { + this.setState({ + loading: false + }) + let _LongParam = '' + if (res.LongParam) { + try { + _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam))) + } catch (e) { + console.warn('Parse Failure') + _LongParam = '' + } + } + + if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') { + param.subConfig = _LongParam + } + + if (param.editTab) { + param.editTab.open_edition = res.open_edition || '' + } + + this.props.handleView(param) + } else { + this.setState({ + loading: false + }) + notification.warning({ + top: 92, + message: res.message, + duration: 5 + }) + } + }) + }, () => { + notification.warning({ + top: 92, + message: this.state.dict['header.menu.config.update'], + duration: 5 + }) + }) + } + } + + /** + * @description 椤甸潰鍚敤鍋滄鍒囨崲 + */ + onEnabledChange = () => { + const { config } = this.state + + let _enabled = !config.enabled + let result = this.verifyconfig(config) + if (_enabled && result !== true) { + notification.warning({ + top: 92, + message: result, + duration: 5 + }) + return + } + + this.setState({ + config: {...config, enabled: _enabled} + }) + } + + /** + * @description 鏍¢獙閰嶇疆淇℃伅鐨勫悎娉曟�� + */ + verifyconfig = (config) => { + let tabinvalid = true + if (config.tabgroups.length > 1) { + config.tabgroups.forEach(group => { + if (group.sublist.length === 0) { + tabinvalid = false + } + }) + } + + if (!config.setting.tableName || !config.setting.valueField || !config.setting.labelField || !config.setting.parentField) { + return '璇峰畬鍠勬爲褰㈢粨鏋勯厤缃俊鎭紒' + } else if (!tabinvalid) { + return '鑿滃崟鏍囩椤佃缃敊璇紙瀛樺湪澶氳鏍囩鏃讹紝琛屾爣绛句笉鍙负绌猴級锛�' + } else { + return true + } + } + + /** + * @description 閫夋嫨涓嶄繚瀛樻椂锛屽鏈夊鍒舵寜閽紝鍒欏垹闄� + */ + notsave = () => { + this.props.handleView() + } + + /** + * @description 缂栬緫鍔熻兘瀹屾垚鏇存柊锛屽寘鎷В鍐绘寜閽�佺矘璐淬�佹浛鎹㈢瓑 + */ + editConfig = (res) => { + if (res.type === 'paste') { + this.setState({ + pasteContent: res.content + }, () => { + this.setState({ + pasteContent: null + }) + }) + } + } + + /** + * @description 鏇存柊鏍囩閰嶇疆淇℃伅 + */ + updatetabs = (config, delcards) => { + const { delTabs } = this.state + + this.setState({ + config: config, + delTabs: delcards ? [...delTabs, ...delcards] : delTabs + }) + } + + /** + * @description 鏇存柊閰嶇疆淇℃伅 + */ + updateconfig = (config) => { + this.setState({ + config: config + }) + } + + render () { + const { activeKey, config } = this.state + + let configTabs = [] + config.tabgroups.forEach(group => { + configTabs.push(...group.sublist) + }) + + return ( + <div className="tree-page-board"> + <DndProvider backend={HTML5Backend}> + {/* 宸ュ叿鏍� */} + <div className="tools"> + <Collapse accordion defaultActiveKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}> + {/* 鍩烘湰淇℃伅 */} + <Panel forceRender={true} header={this.state.dict['header.menu.basedata']} key="0" id="main-basedata"> + {/* 鑿滃崟淇℃伅 */} + <MenuForm + dict={this.state.dict} + formlist={this.state.menuformlist} + wrappedComponentRef={(inst) => this.menuformRef = inst} + /> + </Panel> + {/* 娣诲姞鏍囩 */} + <Panel header={this.state.dict['header.menu.tab']} key="4"> + <div className="search-element"> + {Source.tabItems.map((item, index) => { + return (<SourceElement key={index} content={item}/>) + })} + </div> + {configTabs.length > 0 ? + <p className="config-btn-title"> + <Tooltip placement="topLeft" title="鐐瑰嚮鎸夐挳锛屽彲瀹屾垚鎴栨煡鐪嬫爣绛鹃厤缃俊鎭��"> + <Icon type="question-circle" /> + </Tooltip> + {this.state.dict['header.menu.tab.configurable']} + </p> : null + } + {configTabs.map((item, index) => { + return ( + <div key={index}> + <Button + className="config-button" + icon={item.icon} + style={{marginBottom: '10px'}} + onClick={() => this.setSubConfig(item, 'tab')} + >{item.label}</Button> + </div> + ) + })} + </Panel> + </Collapse> + </div> + <div className="setting"> + <Card title={ + <div> + {this.state.dict['header.menu.page.configurable']} + <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={() => this.reloadTab(true)} /> + </div> + } bordered={false} extra={ + <div> + <EditComponent dict={this.state.dict} type="TreePage" config={this.state.config} MenuID={this.props.menu.MenuID} refresh={this.editConfig}/> + <Switch className="big" checkedChildren="鍚�" unCheckedChildren="鍋�" checked={this.state.config.enabled} onChange={this.onEnabledChange} /> + <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['header.save']}</Button> + <Button onClick={this.cancelConfig}>{this.state.dict['header.return']}</Button> + </div> + } style={{ width: '100%' }}> + <Row gutter={16}> + <Col span={config.setting.width}> + <TreeSettingComponent + config={config} + MenuID={this.props.menu.MenuID} + menuformRef={this.menuformRef} + permFuncField={this.props.permFuncField} + updatesetting={this.updateconfig} + /> + <Card + className="tree-card" + title={ + <span className="tree-title"> + <span className="title">{config.setting.title}</span> + {config.setting.searchable !== 'false' ? <span className="ant-input-search ant-input-affix-wrapper"><span className="ant-input-suffix"><Icon type="search" /></span></span> : null} + </span> + } + bordered={false} + > + <div className="tree-box"> + <Tree + defaultExpandAll={true} + blockNode + showIcon={config.setting.showIcon === 'true'} + showLine={config.setting.showLine === 'true'} + > + <TreeNode icon={<Icon type="folder-open" />} title="parent 0" key="0-0"> + <TreeNode icon={<Icon type="file" />} title="leaf 0-0" key="0-0-0" isLeaf /> + <TreeNode icon={<Icon type="file" />} title="leaf 0-1" key="0-0-1" isLeaf /> + </TreeNode> + <TreeNode icon={<Icon type="folder-open" />} title="parent 1" key="0-1"> + <TreeNode icon={<Icon type="file" />} title="leaf 1-0" key="0-1-0" isLeaf /> + <TreeNode icon={<Icon type="file" />} title="leaf 1-1" key="0-1-1" isLeaf /> + </TreeNode> + </Tree> + </div> + </Card> + </Col> + <Col span={24 - config.setting.width}> + {/* 鏍囩缁� */} + <TabsComponent + config={config} + tabs={this.state.tabviews} + setSubConfig={(item) => this.setSubConfig(item, 'tab')} + updatetabs={this.updatetabs} + /> + </Col> + </Row> + </Card> + </div> + </DndProvider> + {/* 杩斿洖鏃舵湭淇濆瓨鎻愮ず */} + <Modal + bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}} + closable={false} + maskClosable={false} + visible={this.state.closeVisible} + onCancel={() => { this.setState({closeVisible: false}) }} + footer={[ + <Button key="save" className="mk-btn mk-green" loading={this.state.menucloseloading} onClick={this.submitConfig}>{this.state.dict['header.save']}</Button>, + <Button key="notsave" className="mk-btn mk-yellow" onClick={this.notsave}>{this.state.dict['header.notsave']}</Button>, + <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['header.cancel']}</Button> + ]} + destroyOnClose + > + {this.state.dict['header.menu.config.placeholder']} + </Modal> + {this.state.loading && <Spin size="large" />} + </div> + ) + } +} + +const mapStateToProps = (state) => { + return { + sysRoles: state.sysRoles, + permFuncField: state.permFuncField, + memberLevel: state.memberLevel + } +} + +const mapDispatchToProps = () => { + return {} +} + +export default connect(mapStateToProps, mapDispatchToProps)(ComTableConfig) diff --git a/src/templates/treepageconfig/index.scss b/src/templates/treepageconfig/index.scss new file mode 100644 index 0000000..45cb419 --- /dev/null +++ b/src/templates/treepageconfig/index.scss @@ -0,0 +1,266 @@ +.tree-page-board { + position: fixed; + z-index: 1070; + padding-top: 48px; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background: rgba(0, 0, 0, 0.35); + display: flex; + .tools { + flex: 1; + background: #ffffff; + border-right: 1px solid #d9d9d9; + height: 100%; + overflow-y: hidden; + padding-bottom: 30px; + .ant-collapse-item { + position: relative; + border: 0; + } + .ant-input-search { + margin-top: 10px; + } + .ant-collapse-item.ant-collapse-item-active { + border-bottom: 1px solid #d9d9d9; + } + .ant-collapse .ant-collapse-header { + padding: 11px 16px 10px 40px; + border-bottom: 1px solid #d9d9d9; + background: #1890ff; + color: #ffffff; + } + .ant-collapse-content-box { + .ant-form-item { + margin-bottom: 10px; + .ant-form-item-label { + text-align: left; + height: 25px; + line-height: 25px; + } + } + } + .search-element { + padding-top: 10px; + li { + padding: 0px 16px 10px; + div { + cursor: move; + } + } + } + + .ant-list { + margin-top: 20px; + .ant-list-item { + display: -webkit-box; + padding-right: 20px; + position: relative; + padding-left: 5px; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + min-height: 55px; + width: 100%; + .anticon { + position: absolute; + top: 0px; + right: 0px; + padding: 3px 3px 10px 10px; + cursor: pointer; + } + .bottom-mask { + position: absolute; + width: 100%; + height: 8px; + bottom: 0; + left: 0; + background: #ffffff; + border-radius: 8px; + } + } + } + .anticon-question-circle { + color: #c49f47; + margin-right: 3px; + } + .config-button { + min-width: 65px; + } + } + .tools:hover { + overflow-y: auto; + } + .tools::-webkit-scrollbar { + width: 7px; + } + .tools::-webkit-scrollbar-thumb { + border-radius: 5px; + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0); + background: rgba(0, 0, 0, 0); + } + .tools::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0); + border-radius: 3px; + border: 1px solid rgba(0, 0, 0, 0); + background: rgba(0, 0, 0, 0); + } + .tools:hover::-webkit-scrollbar-thumb { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13); + background: rgba(0, 0, 0, 0.13); + } + .tools:hover::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); + border: 1px solid rgba(0, 0, 0, 0.07); + } + .setting { + position: relative; + width: calc(100vw - 235px); + height: 100%; + background: #ffffff; + .ant-switch.big { + min-width: 60px; + height: 28px; + line-height: 28px; + margin-top: -2px; + .ant-switch-inner { + font-size: 14px; + } + } + .ant-switch.big::after { + width: 24px; + height: 24px; + } + .ant-card-head { + min-height: 44px; + } + .ant-card-head-title { + padding: 5px 0; + color: #1890ff; + } + .ant-card-extra { + padding: 5px 0; + button { + margin-left: 20px; + } + } + .ant-card-body { + position: relative; + padding: 10px 10px 40px; + + .tree-card { + min-height: calc(100vh - 125px); + box-shadow: 0px 0px 2px #dddddd; + .ant-card-head { + padding: 0 10px; + .ant-card-head-title { + padding: 15px 0 10px; + .tree-title { + display: inline-block; + width: 100%; + color: #1890ff; + .ant-input-affix-wrapper { + width: calc(100% - 140px); + max-width: 130px; + margin-top: 0px; + float: right; + height: 28px; + border-radius: 20px; + border: 1px solid #d9d9d9; + opacity: 0.6; + } + .title { + display: inline-block; + max-width: 50%; + overflow: hidden; + text-overflow:ellipsis; + white-space: nowrap; + } + } + } + } + >.ant-card-body { + padding: 0px; + .ant-menu-inline { + border-right: 0; + margin-top: 2px; + } + + .tree-box { + min-height: calc(100vh - 180px); + overflow-x: auto; + } + .tree-box::-webkit-scrollbar { + height: 10px; + } + .tree-box::-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); + } + .tree-box::-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); + } + .ant-tree-node-selected + .ant-tree.ant-tree-directory > li span.ant-tree-node-content-wrapper::before, + .ant-tree.ant-tree-directory .ant-tree-child-tree > li span.ant-tree-node-content-wrapper::before { + right: 0px; + } + } + } + + .model-table-tab-list .tab-line-list { + padding-top: 0px; + > .anticon-question-circle { + top: 10px; + } + > .anticon-plus { + top: 15px; + } + > .ant-row .ant-tabs-tab .edit { + top: 10px; + } + .anticon-arrow-down, .anticon-arrow-up, .anticon-delete { + top: 15px; + } + } + .model-tree-menu-setting > .anticon-setting { + font-size: 16px; + right: 0px; + top: -9px; + } + } + } + .setting { + overflow-y: scroll; + } + .setting::-webkit-scrollbar { + width: 7px; + } + .setting::-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); + display: none; + } + .setting::-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); + } + .setting:hover::-webkit-scrollbar-thumb { + display: block; + } + .ant-spin { + position: absolute; + margin-left: calc(50vw - 22px); + margin-top: 30vh; + } +} + diff --git a/src/templates/treepageconfig/source.jsx b/src/templates/treepageconfig/source.jsx new file mode 100644 index 0000000..1b3afed --- /dev/null +++ b/src/templates/treepageconfig/source.jsx @@ -0,0 +1,57 @@ +import Utils from '@/utils/utils.js' +import zhCN from '@/locales/zh-CN/model.js' +import enUS from '@/locales/en-US/model.js' + +const CommonDict = localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS + +class CommonTableBaseData { + baseConfig = { + type: 'system', + Template: 'TreePage', + enabled: false, + setting: { + tableName: '', + title: 'Tree', + order: '', + dataresource: '', + interType: 'inner', + sysInterface: 'false', + searchable: 'true', + innerFunc: '', + interface: '', + outerFunc: '', + width: 5 + }, + tabgroups: [{ + uuid: 'tabs', + sublist: [ + { + origin: true, // 鏄惁涓虹ず渚� + uuid: Utils.getuuid(), + label: 'tab1', + type: 'SubTable', + linkTab: '', + supMenu: '' + }, + { + origin: true, + uuid: Utils.getuuid(), + label: 'tab2', + type: 'SubTable', + linkTab: '', + supMenu: '' + } + ] + }] + } + + tabItems = [ + { + type: 'tabs', + label: CommonDict['header.menu.tab.subtable'], + subType: 'SubTable', + } + ] +} + +export default new CommonTableBaseData() diff --git a/src/templates/zshare/editcomponent/index.jsx b/src/templates/zshare/editcomponent/index.jsx index 25c8cb3..8de343f 100644 --- a/src/templates/zshare/editcomponent/index.jsx +++ b/src/templates/zshare/editcomponent/index.jsx @@ -12,7 +12,7 @@ type: PropTypes.string, MenuID: PropTypes.any, config: PropTypes.object, - thawButtons: PropTypes.array, + thawButtons: PropTypes.any, refresh: PropTypes.func } @@ -185,7 +185,7 @@ render() { const menu = ( <Menu onClick={this.handleMenuClick}> - <Menu.Item key="thaw"><Icon type="unlock" />{this.props.dict['header.form.thawbutton']}</Menu.Item> + {this.props.type !== 'TreePage' ? <Menu.Item key="thaw"><Icon type="unlock" />{this.props.dict['header.form.thawbutton']}</Menu.Item> : null} <Menu.Item key="paste"><Icon type="snippets" />{this.props.dict['header.form.paste']}</Menu.Item> {/* <Menu.Item key="replace"><Icon type="retweet" />鏇挎崲</Menu.Item> */} </Menu> diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx index eb6d5de..2d43a25 100644 --- a/src/templates/zshare/formconfig.jsx +++ b/src/templates/zshare/formconfig.jsx @@ -119,7 +119,7 @@ key: 'dataresource', label: '鏁版嵁婧�', initVal: setting.dataresource || '', - tooltip: '浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩��', + tooltip: '浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\'', help: '鏁版嵁ID锛�' + MenuID, required: false, readonly: false, @@ -232,6 +232,282 @@ { value: 'false', text: '涓嶆墽琛�' } ] }, + ] +} + +/** + * @description 鑾峰彇鏍戝舰椤甸潰璁剧疆琛ㄥ崟閰嶇疆淇℃伅 + * @param {object} setting // 鑿滃崟鍏ㄥ眬璁剧疆淇℃伅 + * @param {string} type // 鑿滃崟绫诲瀷 + */ +export function getTreeSettingForm (setting, usefulFields = [], MenuID) { + let str = '^(' + usefulFields.join('|') + ')' + let _patten = new RegExp(str + formRule.func.innerPattern + '$', 'g') + + return [ + { + type: 'text', + key: 'tableName', + label: '琛ㄥ悕', + initVal: setting.tableName || '', + required: true, + readonly: false, + rules: [ + { + max: formRule.input.max, + message: formRule.input.message + } + ] + }, + { + type: 'text', + key: 'title', + label: '鏍囬', + initVal: setting.title || '', + required: true, + readonly: false, + rules: [ + { + max: formRule.input.max, + message: formRule.input.message + } + ] + }, + { + type: 'radio', + key: 'interType', + label: Formdict['header.form.intertype'], + initVal: setting.interType || 'inner', + required: false, + readonly: false, + options: [ + { value: 'inner', text: Formdict['header.form.interface.inner'] }, + { value: 'outer', text: Formdict['header.form.interface.outer'] } + ] + }, + { + type: 'radio', + key: 'sysInterface', + label: Formdict['header.form.sysInterface'], + initVal: setting.sysInterface || 'false', + required: false, + readonly: false, + options: [ + { value: 'true', text: Formdict['header.form.true'] }, + { value: 'false', text: Formdict['header.form.false'] } + ] + }, + { + type: 'text', + key: 'interface', + label: Formdict['header.form.interface'], + initVal: setting.sysInterface === 'true' ? (window.GLOB.mainSystemApi || '') : (setting.interface || ''), + required: true, + readonly: setting.sysInterface === 'true', + rules: [ + { + max: formRule.input.max, + message: formRule.input.message + } + ] + }, + { + type: 'text', + key: 'outerFunc', + label: Formdict['header.form.outerFunc'], + initVal: setting.outerFunc || '', + required: false, + readonly: false, + rules: [ + { + pattern: formRule.func.pattern, + message: formRule.func.message + }, { + max: formRule.func.max, + message: formRule.func.maxMessage + } + ] + }, + { + type: 'text', + key: 'innerFunc', + label: Formdict['header.form.innerFunc'], + initVal: setting.innerFunc || '', + tooltip: '寮�澶村彲鐢ㄥ瓧绗︼細' + usefulFields.join(', '), + placement: 'bottomLeft', + required: false, + readonly: false, + rules: [ + { + pattern: _patten, + message: formRule.func.innerMessage + }, { + max: formRule.func.max, + message: formRule.func.maxMessage + } + ] + }, + { + type: 'datasource', + key: 'dataresource', + label: '鏁版嵁婧�', + initVal: setting.dataresource || '', + tooltip: '浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\'', + help: '鏁版嵁ID锛�' + MenuID, + required: false, + readonly: false, + rules: [ + { + pattern: _patten, + message: formRule.func.innerMessage + }, { + max: formRule.func.max, + message: formRule.func.maxMessage + } + ] + }, + { + type: 'text', + key: 'valueField', + label: 'Value', + initVal: setting.valueField || '', + tooltip: '鏁版嵁鍊煎瓧娈点��', + required: true, + readonly: false, + rules: [ + { + pattern: formRule.field.pattern, + message: formRule.field.message + }, { + max: formRule.field.max, + message: formRule.field.maxMessage + } + ] + }, + { + type: 'text', + key: 'labelField', + label: 'Label', + initVal: setting.labelField || '', + tooltip: '鏄剧ず鏂囧瓧瀛楁銆�', + required: true, + readonly: false, + rules: [ + { + pattern: formRule.field.pattern, + message: formRule.field.message + }, { + max: formRule.field.max, + message: formRule.field.maxMessage + } + ] + }, + { + type: 'text', + key: 'parentField', + label: 'Parent', + initVal: setting.parentField || '', + tooltip: '鐖剁骇瀛楁銆�', + required: true, + readonly: false, + rules: [ + { + pattern: formRule.field.pattern, + message: formRule.field.message + }, { + max: formRule.field.max, + message: formRule.field.maxMessage + } + ] + }, + { + type: 'text', + key: 'order', + label: '鎺掑簭', + initVal: setting.order || '', + placeholder: 'ID asc, UID desc', + required: true, + readonly: false, + rules: [ + { + max: formRule.input.max, + message: formRule.input.message + } + ] + }, + { + type: 'text', + key: 'mark', + label: '椤剁骇鏍囪瘑', + initVal: setting.mark || '', + tooltip: '鐖剁骇瀛楁鍊间笌椤剁骇鏍囪瘑锛堥粯璁ゅ�间负绌猴級鐩稿悓鏃讹紝瑙嗕负椤剁骇鑺傜偣銆�', + required: false, + readonly: false, + rules: [ + { + max: formRule.input.max, + message: formRule.input.message + } + ] + }, + { + type: 'number', + key: 'width', + min: 2, + max: 12, + label: '瀹藉害', + tooltip: '姣忚鍒嗕负24浠斤紝鏍戝舰姣斾緥鍙缃负2-12锛堟渶澶�50%锛�', + initVal: setting.width || 5, + required: true + }, + { + type: 'radio', + key: 'searchable', + label: '鎼滅储', + initVal: setting.searchable || 'true', + required: false, + readonly: false, + options: [ + { value: 'true', text: '鏄剧ず' }, + { value: 'false', text: '闅愯棌' } + ] + }, + { + type: 'radio', + key: 'default', + label: '榛樿sql', + initVal: setting.default || 'true', + required: false, + readonly: false, + options: [ + { value: 'true', text: '鎵ц' }, + { value: 'false', text: '涓嶆墽琛�' } + ] + }, + { + type: 'radio', + key: 'showIcon', + label: '鏄剧ず鍥炬爣', + initVal: setting.showIcon || 'false', + required: false, + readonly: false, + options: [ + { value: 'true', text: Formdict['header.form.true'] }, + { value: 'false', text: Formdict['header.form.false'] } + ] + }, + { + type: 'radio', + key: 'showLine', + label: '鏄剧ず鍒嗗壊绾�', + initVal: setting.showLine || 'false', + required: false, + readonly: false, + options: [ + { value: 'true', text: Formdict['header.form.true'] }, + { value: 'false', text: Formdict['header.form.false'] } + ] + } ] } @@ -687,6 +963,20 @@ }) } + let refresh = [] + if (type === 'subtable') { // 瀛愯〃椤甸潰锛屽彲璁剧疆鍒锋柊涓昏〃鍙婂悓绾ф爣绛� + refresh.push({ + value: 'maingrid', + text: Formdict['header.form.refresh.maingrid'] + }, { + value: 'equaltab', + text: Formdict['header.form.refresh.equaltab'] + }, { + value: 'mainline', + text: Formdict['header.form.refresh.mainline'] + }) + } + return [ { type: 'select', @@ -928,7 +1218,8 @@ }, { value: 'view', text: Formdict['header.form.refresh.view'] - }] + }, + ...refresh] }, { type: 'select', @@ -962,7 +1253,8 @@ }, { value: 'view', text: Formdict['header.form.refresh.view'] - }] + }, + ...refresh] }, { type: 'select', @@ -2142,13 +2434,24 @@ required: false }, { + type: 'number', + key: 'level', + label: '鏄剧ず绾у埆', + tooltip: '鏍囩鏄剧ず鎺у埗锛岄�夋嫨鎸囧畾绾у埆鏃舵樉绀烘爣绛撅紝绾у埆涓虹┖鏃跺缁堟樉绀恒��', + initVal: card.level, + min: 1, + max: 10, + required: false, + forbid: type !== 'TreePage', + }, + { type: 'radio', key: 'searchPass', label: '涓昏〃鎼滅储', initVal: card.searchPass || 'false', tooltip: '浣跨敤涓昏〃鎼滅储鏉′欢鏃讹紝涓昏〃鐨勬悳绱㈡潯浠朵細浼犲叆瀛愯〃涓��', required: false, - forbid: type !== 'main', + forbid: type !== 'CommonTable', options: [{ value: 'true', text: '浣跨敤' diff --git a/src/utils/option.js b/src/utils/option.js index fd91b87..769ea29 100644 --- a/src/utils/option.js +++ b/src/utils/option.js @@ -62,6 +62,13 @@ isSubtable: true }, { + title: '鏍戝舰椤甸潰', + type: 'TreePage', + url: mainsubtable, + baseconfig: '', + isSystem: true + }, + { title: '瑙掕壊鏉冮檺鍒嗛厤', type: 'RolePermission', url: rolemanage, diff --git a/src/utils/utils.js b/src/utils/utils.js index 3a918f8..dd981d9 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -67,10 +67,10 @@ {key: 'alter', reg: /(^|\s)alter\s/ig}, {key: 'truncate', reg: /(^|\s)truncate\s/ig}, {key: 'if', reg: /(^|\s)if\s/ig}, - {key: 'exec', reg: /exec/ig}, - {key: 'OBJECT', reg: /object/ig}, - {key: 'sys.', reg: /sys\./ig}, - {key: 'kill', reg: /kill/ig} + {key: 'exec', reg: /(^|\s)exec(\s|\()/ig}, + {key: 'OBJECT', reg: /(^|\s)object(\s|\()/ig}, + {key: 'sys.', reg: /(^|\s)sys\./ig}, + {key: 'kill', reg: /(^|\s)kill\s/ig} ] if (type === 'customscript') { -- Gitblit v1.8.0