提交 1438af9f 作者: 郁骅焌

增加tab新增编辑页

上级 22f289ea
...@@ -3,7 +3,10 @@ const routes = [ ...@@ -3,7 +3,10 @@ const routes = [
'/system/menu', '/system/menu',
'/system/dept', '/system/dept',
'/system/user', '/system/user',
'/system/center' '/system/center',
'/demo/tabcrud',
'/demo/tabcrud/add',
'/demo/tabcrud/edit'
] ]
export default { export default {
......
...@@ -116,6 +116,22 @@ export default defineConfig({ ...@@ -116,6 +116,22 @@ export default defineConfig({
icon: 'SolutionOutlined', icon: 'SolutionOutlined',
component: './demo/crud', component: './demo/crud',
}, },
{
path: '/demo/tabcrud',
name: 'tabcrud',
icon: 'SolutionOutlined',
component: './demo/tabcrud',
},
{
path: '/demo/tabcrud/add',
name: 'crudadd',
component: './demo/tabcrud/components/CreateForm',
},
{
path: '/demo/tabcrud/edit',
name: 'crudedit',
component: './demo/tabcrud/components/UpdateForm',
},
], ],
}, },
{ {
......
...@@ -13,5 +13,5 @@ export default { ...@@ -13,5 +13,5 @@ export default {
}, },
title: 'Sage Framework', title: 'Sage Framework',
pwa: false, pwa: false,
iconfontUrl: '', iconfontUrl: '//at.alicdn.com/t/font_1873986_zq2zexdsrnm.js',
}; };
import React from 'react'
import { Card } from 'antd'
import './style.less'
/**
*
* @param props
*/
const SageCard = (props) => {
const componentProps = {
...props
}
return (
<Card {...componentProps} />
)
}
export default SageCard
...@@ -24,6 +24,8 @@ import SimplePictureUpload from '../Upload/SimplePictureUpload' ...@@ -24,6 +24,8 @@ import SimplePictureUpload from '../Upload/SimplePictureUpload'
import MultiplePictureUpload from '../Upload/MultiplePictureUpload' import MultiplePictureUpload from '../Upload/MultiplePictureUpload'
import NormalUpload from '../Upload/NormalUpload' import NormalUpload from '../Upload/NormalUpload'
import './style.less'
const { TextArea } = Input const { TextArea } = Input
const { Option } = Select const { Option } = Select
const { MonthPicker, RangePicker } = DatePicker const { MonthPicker, RangePicker } = DatePicker
...@@ -87,7 +89,12 @@ const SageForm = (props, ref) => { ...@@ -87,7 +89,12 @@ const SageForm = (props, ref) => {
const { const {
formFields, formFields,
colNum = 1, colNum = 1,
showSubmitButton = false, showButtonRow = false, // 是否显示按钮行
showSubmitButton = false, // 是否显示提交按钮
showReturnButton = false, // 是否显示取消按钮
submitText = '提交',
returnText = '返回',
onReturn,
tailLayout = { tailLayout = {
wrapperCol: { offset: 4, span: 20 } wrapperCol: { offset: 4, span: 20 }
}, },
...@@ -96,6 +103,12 @@ const SageForm = (props, ref) => { ...@@ -96,6 +103,12 @@ const SageForm = (props, ref) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
// const onReturn = () => {
// if (props.onReturn) {
// props.onReturn()
// }
// }
// 暴露外部方法 // 暴露外部方法
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
submit: () => form.submit(), submit: () => form.submit(),
...@@ -245,18 +258,28 @@ const SageForm = (props, ref) => { ...@@ -245,18 +258,28 @@ const SageForm = (props, ref) => {
// initialValues={{ remember: true }} // initialValues={{ remember: true }}
validateMessages={validateMessages} validateMessages={validateMessages}
{...formProps} {...formProps}
className="sage-form"
> >
<Row span={24}> <Row span={24}>
{formNode} {formNode}
</Row> </Row>
{ {
showSubmitButton ? showButtonRow ?
<Row span={24}> <Row span={24}>
<Col span={24}> <Col span={24}>
<Form.Item {...tailLayout}> <Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit"> {
保存 showSubmitButton ?
</Button> <Button type="primary" htmlType="submit" className="sage-form-buttn">
{submitText}
</Button> : null
}
{
showReturnButton ?
<Button htmlType="button" onClick={() => onReturn && onReturn()} className="sage-form-buttn">
{returnText}
</Button> : null
}
</Form.Item> </Form.Item>
</Col> </Col>
</Row> : null </Row> : null
......
.sage-form {
.sage-form-buttn {
margin-right: 8px;
}
}
...@@ -76,7 +76,7 @@ const SageTable = React.forwardRef((props, ref) => { ...@@ -76,7 +76,7 @@ const SageTable = React.forwardRef((props, ref) => {
const { isFullscreen, setFull, exitFull } = useFullscreen({ const { isFullscreen, setFull, exitFull } = useFullscreen({
dom: () => document.getElementsByClassName('ant-pro-page-header-wrap-children-content')[0], dom: () => document.getElementsByClassName('ant-pro-page-header-wrap-children-content')[0],
}); });
const [tableSize, setTableSize] = useState('default'); const [tableSize, setTableSize] = useState('small');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [tableState, setTableState] = useState(initState); const [tableState, setTableState] = useState(initState);
......
...@@ -5,6 +5,7 @@ import SageModal from './Modal' ...@@ -5,6 +5,7 @@ import SageModal from './Modal'
import SageForm from './Form' import SageForm from './Form'
import SageTree from './Tree' import SageTree from './Tree'
import SageMessage from './Message' import SageMessage from './Message'
import SageCard from './Card'
import SageLayoutLR from './Layout/LayoutLR' import SageLayoutLR from './Layout/LayoutLR'
export { export {
...@@ -15,5 +16,6 @@ export { ...@@ -15,5 +16,6 @@ export {
SageModal, SageModal,
SageForm, SageForm,
SageTree, SageTree,
SageMessage SageMessage,
SageCard
} }
import React, { useState, useEffect, useImperativeHandle } from 'react'; import React, { useState, useEffect, useImperativeHandle } from 'react';
import { Tabs, Menu, Dropdown, Button } from 'antd'; import { Tabs, Menu, Dropdown, Button } from 'antd';
import { ReloadOutlined } from '@ant-design/icons'; import { ReloadOutlined } from '@ant-design/icons';
import { useLocation, useIntl, history, dropByCacheKey } from 'umi'; import { useLocation, useIntl, history, dropByCacheKey, connect } from 'umi';
import './style.less'; import './style.less';
const { REACT_APP_ENV } = process.env; const { REACT_APP_ENV } = process.env;
const { TabPane } = Tabs; const { TabPane } = Tabs;
const TabBar = (props, ref) => { const TabBar = (props) => {
const location = useLocation(); const location = useLocation();
const { pathname } = location; const { pathname } = location;
const { const {
menuTree menuTree,
tabActiveKey,
tabPanes,
allPath
} = props; } = props;
const [panes, setPanes] = useState([ // const [panes, setPanes] = useState([
{ title: '首页', key: '/home', closable: false }, // { title: '首页', key: '/home', closable: false },
// { title: '测试标签1', key: '2' }, // // { title: '测试标签1', key: '2' },
// { title: '测试标签2', key: '3' }, // // { title: '测试标签2', key: '3' },
// { title: 'Crud', key: '/demo/crud' }, // // { title: 'Crud', key: '/demo/crud' },
// { title: '测试标签3', key: '4' }, // // { title: '测试标签3', key: '4' },
// { title: '测试标签4', key: '5' }, // // { title: '测试标签4', key: '5' },
// { title: '测试标签5', key: '6' }, // // { title: '测试标签5', key: '6' },
// { title: '测试标签6', key: '7' }, // // { title: '测试标签6', key: '7' },
// { title: '测试标签7', key: '8' }, // // { title: '测试标签7', key: '8' },
// { title: '测试标签8', key: '9' }, // // { title: '测试标签8', key: '9' },
// { title: '测试标签9', key: '10' }, // // { title: '测试标签9', key: '10' },
// { title: '测试标签10', key: '11' }, // // { title: '测试标签10', key: '11' },
// { title: '测试标签11', key: '12' }, // // { title: '测试标签11', key: '12' },
// { title: '测试标签12', key: '13' } // // { title: '测试标签12', key: '13' }
]); // ]);
const [activeKey, setActiveKey] = useState(''); // const [activeKey, setActiveKey] = useState('');
const [allPath, setAllPath] = useState([]); // const [allPath, setAllPath] = useState([]);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const checkPaneExist = (path) => { const checkPaneExist = (path) => {
let isExist = false; let isExist = false;
for (let i = 0; i < panes.length; i++) { for (let i = 0; i < tabPanes.length; i++) {
if (panes[i].key === path) { if (tabPanes[i].key === path) {
isExist = true; isExist = true;
break; break;
} }
...@@ -49,12 +52,18 @@ const TabBar = (props, ref) => { ...@@ -49,12 +52,18 @@ const TabBar = (props, ref) => {
return item.path === path; return item.path === path;
}); });
if (p) { if (p) {
const newPanes = panes.slice(); const newPanes = tabPanes.slice();
newPanes.push({ newPanes.push({
title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName, title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName,
key: path, key: path,
}); });
setPanes(newPanes); props.dispatch({
type: 'global/updateState',
payload: {
tabPanes: newPanes
}
})
// setPanes(newPanes);
} }
} }
}; };
...@@ -72,11 +81,17 @@ const TabBar = (props, ref) => { ...@@ -72,11 +81,17 @@ const TabBar = (props, ref) => {
}); });
}; };
loopPath(menuTree || []); loopPath(menuTree || []);
setAllPath(list); props.dispatch({
type: 'global/updateState',
payload: {
allPath: list
}
})
// setAllPath(list);
let isExist = false; let isExist = false;
for (let i = 0; i < panes.length; i++) { for (let i = 0; i < tabPanes.length; i++) {
if (panes[i].key === pathname) { if (tabPanes[i].key === pathname) {
isExist = true; isExist = true;
break; break;
} }
...@@ -86,25 +101,49 @@ const TabBar = (props, ref) => { ...@@ -86,25 +101,49 @@ const TabBar = (props, ref) => {
return item.path === pathname; return item.path === pathname;
}); });
if (p) { if (p) {
const newPanes = panes.slice(); const newPanes = tabPanes.slice();
newPanes.push({ newPanes.push({
title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName, title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName,
key: pathname, key: pathname,
}); });
setPanes(newPanes); props.dispatch({
type: 'global/updateState',
payload: {
tabPanes: newPanes
}
})
// setPanes(newPanes);
} }
} }
setActiveKey(pathname); props.dispatch({
type: 'global/updateState',
payload: {
tabActiveKey: pathname
}
})
// setActiveKey(pathname);
}, []); }, []);
const onChange = (activekey, fromMenu) => { const onChange = (activekey, fromMenu) => {
if (activekey !== activeKey) { if (activekey !== tabActiveKey) {
// setTimeout(() => { // setTimeout(() => {
setActiveKey(activekey); props.dispatch({
type: 'global/updateState',
payload: {
tabActiveKey: activekey
}
})
// setActiveKey(activekey);
// }, 200) // }, 200)
if (!fromMenu) { if (!fromMenu) {
props.setSelectedKeys([activekey]) props.dispatch({
type: 'global/updateState',
payload: {
menuSelectedKeys: [activekey]
}
})
// props.setSelectedKeys([activekey])
props.checkMenuOpen(activekey) props.checkMenuOpen(activekey)
history.push(activekey); history.push(activekey);
} else { } else {
...@@ -116,13 +155,13 @@ const TabBar = (props, ref) => { ...@@ -116,13 +155,13 @@ const TabBar = (props, ref) => {
const remove = (targetKey) => { const remove = (targetKey) => {
let lastActiveKey = '/home'; let lastActiveKey = '/home';
let lastIndex; let lastIndex;
panes.forEach((pane, i) => { tabPanes.forEach((pane, i) => {
if (pane.key === targetKey) { if (pane.key === targetKey) {
lastIndex = i - 1; lastIndex = i - 1;
} }
}); });
const lastPanes = panes.filter((pane) => pane.key !== targetKey); const lastPanes = tabPanes.filter((pane) => pane.key !== targetKey);
if (lastPanes.length && activeKey === targetKey) { if (lastPanes.length && tabActiveKey === targetKey) {
if (lastIndex >= 0) { if (lastIndex >= 0) {
lastActiveKey = lastPanes[lastIndex].key; lastActiveKey = lastPanes[lastIndex].key;
} else { } else {
...@@ -132,10 +171,24 @@ const TabBar = (props, ref) => { ...@@ -132,10 +171,24 @@ const TabBar = (props, ref) => {
lastActiveKey = lastPanes[lastPanes.length - 1].key; lastActiveKey = lastPanes[lastPanes.length - 1].key;
} }
// setTimeout(() => { // setTimeout(() => {
setActiveKey(lastActiveKey); props.dispatch({
type: 'global/updateState',
payload: {
tabActiveKey: lastActiveKey,
menuSelectedKeys: [lastActiveKey],
tabPanes: lastPanes
}
})
// setActiveKey(lastActiveKey);
// }, 200) // }, 200)
setPanes(lastPanes); // props.dispatch({
props.setSelectedKeys([lastActiveKey]) // type: 'global/updateState',
// payload: {
// tabPanes: lastPanes
// }
// })
// setPanes(lastPanes);
// props.setSelectedKeys([lastActiveKey])
props.checkMenuOpen(lastActiveKey) props.checkMenuOpen(lastActiveKey)
history.push(lastActiveKey); history.push(lastActiveKey);
}; };
...@@ -149,8 +202,8 @@ const TabBar = (props, ref) => { ...@@ -149,8 +202,8 @@ const TabBar = (props, ref) => {
// 刷新 // 刷新
const refreshTab = (e) => { const refreshTab = (e) => {
e.preventDefault(); e.preventDefault();
dropByCacheKey(activeKey); dropByCacheKey(tabActiveKey);
history.push(activeKey); history.push(tabActiveKey);
}; };
const menu = ( const menu = (
...@@ -161,30 +214,30 @@ const TabBar = (props, ref) => { ...@@ -161,30 +214,30 @@ const TabBar = (props, ref) => {
</Menu> </Menu>
); );
const getPanes = () => { // const getPanes = () => {
return panes // return panes
} // }
// 暴露外部方法 // 暴露外部方法
useImperativeHandle(ref, () => ({ // useImperativeHandle(ref, () => ({
onChange, // onChange,
getPanes, // getPanes,
setPanes, // setPanes,
setActiveKey // setActiveKey
})); // }));
return ( return (
<div className="sage-tabbar"> <div className="sage-tabbar">
<div className="sage-tabbar-left"> <div className="sage-tabbar-left">
<Tabs <Tabs
onChange={onChange} onChange={onChange}
activeKey={activeKey} activeKey={tabActiveKey}
type="editable-card" type="editable-card"
hideAdd hideAdd
tabBarGutter={4} tabBarGutter={4}
onEdit={onEdit} onEdit={onEdit}
> >
{panes.map((pane) => ( {tabPanes.map((pane) => (
<TabPane tab={pane.title} key={pane.key} closable={pane.closable} /> <TabPane tab={pane.title} key={pane.key} closable={pane.closable} />
))} ))}
</Tabs> </Tabs>
...@@ -198,4 +251,11 @@ const TabBar = (props, ref) => { ...@@ -198,4 +251,11 @@ const TabBar = (props, ref) => {
); );
}; };
export default React.forwardRef(TabBar); export default connect(({ global }) => ({
collapsed: global.collapsed,
menuSelectedKeys: global.menuSelectedKeys,
menuOpenKeys: global.menuOpenKeys,
tabActiveKey: global.tabActiveKey,
tabPanes: global.tabPanes,
allPath: global.allPath
}))(TabBar);
export default {
IconUrl: '//at.alicdn.com/t/font_1873986_zq2zexdsrnm.js'
}
...@@ -13,17 +13,12 @@ import RightContent from '@/components/GlobalHeader/RightContent'; ...@@ -13,17 +13,12 @@ import RightContent from '@/components/GlobalHeader/RightContent';
import TabBar from '@/components/TabBar'; import TabBar from '@/components/TabBar';
import GlobalFooter from '@/components/GlobalFooter'; import GlobalFooter from '@/components/GlobalFooter';
import { getAuthorityFromRouter } from '@/utils/utils'; import { getAuthorityFromRouter } from '@/utils/utils';
import config from '@/config.js'
import logo from '../assets/logo.svg'; import logo from '../assets/logo.svg';
import './BasicLayout.less' import './BasicLayout.less'
const { REACT_APP_ENV } = process.env; const { REACT_APP_ENV } = process.env;
const IconFont = createFromIconfontCN({
scriptUrl: config.IconUrl,
});
const { SubMenu } = Menu; const { SubMenu } = Menu;
const noMatch = ( const noMatch = (
...@@ -84,17 +79,24 @@ const BasicLayout = (props) => { ...@@ -84,17 +79,24 @@ const BasicLayout = (props) => {
}, },
currentUser, currentUser,
route, route,
collapsed collapsed,
menuSelectedKeys,
menuOpenKeys,
// tabActiveKey
} = props; } = props;
const [selectedKeys, setSelectedKeys] = useState([location.pathname]) // const [selectedKeys, setSelectedKeys] = useState([location.pathname])
const [openKeys, setOpenKeys] = useState([]) // const [openKeys, setOpenKeys] = useState([])
const IconFont = createFromIconfontCN({
scriptUrl: settings.iconfontUrl,
});
/** /**
* constructor * constructor
*/ */
const tabBarRef = useRef(); // const tabBarRef = useRef();
const handleMenuCollapse = (payload) => { const handleMenuCollapse = (payload) => {
if (dispatch) { if (dispatch) {
...@@ -105,11 +107,11 @@ const BasicLayout = (props) => { ...@@ -105,11 +107,11 @@ const BasicLayout = (props) => {
} }
}; // get children authority }; // get children authority
const handlePageChange = ({ pathname }) => { // const handlePageChange = ({ pathname }) => {
if (tabBarRef.current) { // if (tabBarRef.current) {
tabBarRef.current.onChange(pathname, true); // tabBarRef.current.onChange(pathname, true);
} // }
}; // };
const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || { const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || {
authority: undefined, authority: undefined,
...@@ -194,15 +196,36 @@ const BasicLayout = (props) => { ...@@ -194,15 +196,36 @@ const BasicLayout = (props) => {
// 选中菜单 // 选中菜单
const handleSelectMenu = ({item, key}) => { const handleSelectMenu = ({item, key}) => {
setSelectedKeys([key]) props.dispatch({
history.push(key) type: 'global/updateState',
if (tabBarRef.current) { payload: {
tabBarRef.current.onChange(key, true); menuSelectedKeys: [key],
tabActiveKey: key
} }
})
// setSelectedKeys([key])
props.dispatch({
type: 'global/checkPaneExist',
payload: {
path: key
}
})
history.push(key)
// if (tabBarRef.current) {
// tabBarRef.current.onChange(key, true);
// }
} }
const handleOpenChange = (_openKeys) => { const handleOpenChange = (_openKeys) => {
setOpenKeys(_openKeys.length > 1 ? [_openKeys.slice().pop()] : _openKeys) props.dispatch({
type: 'global/updateState',
payload: {
menuOpenKeys: _openKeys.length > 1 ? [_openKeys.slice().pop()] : _openKeys
}
})
// setOpenKeys(_openKeys.length > 1 ? [_openKeys.slice().pop()] : _openKeys)
} }
const menuTree = useMemo(() => getMenuTree(), []) const menuTree = useMemo(() => getMenuTree(), [])
...@@ -213,7 +236,13 @@ const BasicLayout = (props) => { ...@@ -213,7 +236,13 @@ const BasicLayout = (props) => {
for (let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
if (list[i].path === key) { if (list[i].path === key) {
if (list[i].parentPath) { if (list[i].parentPath) {
setOpenKeys([list[i].parentPath]) props.dispatch({
type: 'global/updateState',
payload: {
menuOpenKeys: [list[i].parentPath]
}
})
// setOpenKeys([list[i].parentPath])
} }
// setOpenKeys(list[i].parentPath ? [list[i].parentPath] : []) // setOpenKeys(list[i].parentPath ? [list[i].parentPath] : [])
break break
...@@ -227,15 +256,15 @@ const BasicLayout = (props) => { ...@@ -227,15 +256,15 @@ const BasicLayout = (props) => {
} }
useEffect(() => { useEffect(() => {
const currentPath = location.pathname
props.dispatch({
type: 'global/updateState',
payload: {
menuSelectedKeys: [currentPath]
}
})
checkMenuOpen(currentPath)
checkMenuOpen(selectedKeys[0])
// if (dispatch) {
// dispatch({
// type: 'user/fetchCurrent',
// });
// }
// document.getElementsByClassName('ant-layout-header')[0].style.width = 'calc(100% - 256px)'
// document.getElementsByClassName('sage-tabbar')[0].style.width = 'calc(100% - 256px)'
}, []); }, []);
/** /**
* init variables * init variables
...@@ -270,8 +299,8 @@ const BasicLayout = (props) => { ...@@ -270,8 +299,8 @@ const BasicLayout = (props) => {
<div> <div>
<Menu <Menu
style={{ width: '100%' }} style={{ width: '100%' }}
selectedKeys={selectedKeys} selectedKeys={menuSelectedKeys}
openKeys={openKeys} openKeys={menuOpenKeys}
mode="inline" mode="inline"
theme="dark" theme="dark"
onSelect={handleSelectMenu} onSelect={handleSelectMenu}
...@@ -295,10 +324,10 @@ const BasicLayout = (props) => { ...@@ -295,10 +324,10 @@ const BasicLayout = (props) => {
<RightContent goCenter={goCenter} /> <RightContent goCenter={goCenter} />
</div> </div>
<TabBar <TabBar
ref={tabBarRef} // ref={tabBarRef}
currentUser={currentUser} currentUser={currentUser}
menuTree={menuTree} menuTree={menuTree}
setSelectedKeys={setSelectedKeys} // setSelectedKeys={setSelectedKeys}
checkMenuOpen={checkMenuOpen} checkMenuOpen={checkMenuOpen}
/> />
</div> </div>
...@@ -366,5 +395,8 @@ const BasicLayout = (props) => { ...@@ -366,5 +395,8 @@ const BasicLayout = (props) => {
export default connect(({ user, global, settings }) => ({ export default connect(({ user, global, settings }) => ({
currentUser: user.currentUser, currentUser: user.currentUser,
collapsed: global.collapsed, collapsed: global.collapsed,
menuSelectedKeys: global.menuSelectedKeys,
menuOpenKeys: global.menuOpenKeys,
tabActiveKey: global.tabActiveKey,
settings, settings,
}))(BasicLayout); }))(BasicLayout);
import { history, dropByCacheKey } from 'umi'
import { queryNotices } from '@/services/user'; import { queryNotices } from '@/services/user';
const GlobalModel = { const GlobalModel = {
...@@ -5,6 +6,13 @@ const GlobalModel = { ...@@ -5,6 +6,13 @@ const GlobalModel = {
state: { state: {
collapsed: false, collapsed: false,
notices: [], notices: [],
menuSelectedKeys: [],
menuOpenKeys: [],
tabActiveKey: '',
tabPanes: [
{ title: '首页', key: '/home', closable: false }
],
allPath: []
}, },
effects: { effects: {
*fetchNotices(_, { call, put, select }) { *fetchNotices(_, { call, put, select }) {
...@@ -67,8 +75,127 @@ const GlobalModel = { ...@@ -67,8 +75,127 @@ const GlobalModel = {
}, },
}); });
}, },
// 跳转tab
*goTab({ payload }, { put, select }) {
const globalState = yield select(state => state.global)
const newState = {}
newState.menuSelectedKeys = [payload.path]
newState.tabActiveKey = payload.path
let isExist = false;
for (let i = 0; i < globalState.tabPanes.length; i++) {
if (globalState.tabPanes[i].key === payload.path) {
isExist = true;
break;
}
}
if (!isExist) {
const newPanes = globalState.tabPanes.slice();
newPanes.push({
// title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName,
title: payload.name,
key: payload.path,
});
newState.tabPanes = newPanes
}
if (payload.query) {
history.push({
pathname: payload.path,
query: payload.query
});
} else {
history.push(payload.path)
}
yield put({
type: 'updateState',
payload: {
...newState
},
});
},
// 返回tab
*returnTab({ payload }, { put, select }) {
const globalState = yield select(state => state.global)
dropByCacheKey(payload.closePath)
const tabPanes = globalState.tabPanes.slice()
let removeIndex;
tabPanes.forEach((pane, i) => {
if (pane.key === payload.closePath) {
removeIndex = i;
}
});
tabPanes.splice(removeIndex, 1)
const newState = {}
newState.menuSelectedKeys = [payload.returnPath]
newState.tabActiveKey = payload.returnPath
let isExist = false;
for (let i = 0; i < tabPanes.length; i++) {
if (tabPanes[i].key === payload.returnPath) {
isExist = true;
break;
}
}
if (!isExist) {
const newPanes = tabPanes.slice();
newPanes.push({
// title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName,
title: payload.returnName,
key: payload.returnPath,
});
newState.tabPanes = newPanes
} else {
newState.tabPanes = tabPanes
}
history.push(payload.returnPath)
yield put({
type: 'updateState',
payload: {
...newState
},
});
},
}, },
reducers: { reducers: {
updateState(state, { payload }) {
return {...state, ...payload}
},
checkPaneExist(state, { payload }) {
let isExist = false;
for (let i = 0; i < state.tabPanes.length; i++) {
if (state.tabPanes[i].key === payload.path) {
isExist = true;
break;
}
}
if (!isExist) {
const p = state.allPath.find((item) => {
return item.path === payload.path;
});
if (p) {
const newPanes = state.tabPanes.slice();
newPanes.push({
// title: REACT_APP_ENV === 'dev' ? formatMessage({id: p.menuName}) : p.menuName,
title: p.menuName,
key: payload.path,
});
return {...state, tabPanes: newPanes}
// setPanes(newPanes);
}
}
return {
...state
}
},
changeLayoutCollapsed( changeLayoutCollapsed(
state = { state = {
notices: [], notices: [],
......
import React, { useState, useRef, useEffect } from 'react'
import { connect, dropByCacheKey } from 'umi'
import { Form, Input, InputNumber, Select, AutoComplete, Spin } from 'antd'
import { SageCard, SageForm, SageMessage } from '@/components/Common'
import { getEnumDropDownList } from '@/services/enum'
import { addCrud } from '../service';
const { Option } = Select
const CreateForm = (props) => {
const { location } = props
const formRef = useRef()
// 初始化数据
const [loading, setLoading] = useState(false)
const [selectOptions1, setSelectOptions1] = useState([])
const [selectOptions2, setSelectOptions2] = useState([])
// 初始化下拉数据
const initSelectOptions = async () => {
const res = await getEnumDropDownList({
code: 'DEVICE_CONTROL_TYPE,DEVICE_FUNCTION_TYPE'
})
if (res.isSuccess) {
const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data
DEVICE_CONTROL_TYPE && DEVICE_CONTROL_TYPE.forEach(item => {
item.text = item.dictValue
item.value = item.dictKey
})
DEVICE_FUNCTION_TYPE && DEVICE_FUNCTION_TYPE.forEach(item => {
item.text = item.dictValue
item.value = item.dictKey
})
setSelectOptions1(DEVICE_CONTROL_TYPE || [])
setSelectOptions2(DEVICE_FUNCTION_TYPE || [])
}
}
useEffect(() => {
initSelectOptions()
}, [])
// 上传成功
const uploadSuccess = (field, value) => {
formRef.current.setFieldsValue({ [field]: value })
}
// 返回
const onReturn = () => {
props.dispatch({
type: 'global/returnTab',
payload: {
closePath: location.pathname,
returnPath: '/demo/tabcrud',
returnName: 'TabCrud'
}
})
}
const onFinish = async (values) => {
const formData = Object.assign({}, values)
console.log('提交数据:', formData)
// 处理赋值表单数据
formData.field1 = '字段1的值'
// 多字段
formData.field8 = values.field89.field8
formData.field9 = values.field89.field9
delete formData.field89
// 开关
formData.field12 = values.field12 ? '1' : '0'
// 时间
formData.field19 = values.field19 ? values.field19.format('YYYY-MM-DD') : ''
formData.field22 = values.field22 ? values.field22.format('YYYY-MM-DD HH:mm:ss') : ''
formData.field23 = values.field23 ? values.field23.format('YYYY-MM') : ''
formData.field24 = values.field24 ? [values.field24[0].format('YYYY-MM-DD'), values.field24[1].format('YYYY-MM-DD')] : []
formData.field25 = values.field25 ? values.field25.format('HH:mm:ss') : ''
setLoading(true)
const res = await addCrud(formData)
setLoading(false)
if (res.isSuccess) {
SageMessage.success('保存成功')
dropByCacheKey('/demo/tabcrud')
onReturn()
}
}
const onFinishFailed = ({ values }) => {
console.log(values)
}
// 表单字段设置
const formFields = [
{
name: 'field1',
label: '字段1',
type: 'text',
props: {
value: '字段1的值'
}
},
{
name: 'field2',
label: '字段2',
type: 'input',
rules: [{ required: true }],
props: {
placeholder: '请输入'
}
},
{
name: 'field3',
label: '字段3', // (固定下拉数据)
type: 'select',
rules: [{ required: true }],
options: [
{ text: '选项1', value: 'select1' },
{ text: '选项2', value: 'select2' }
],
props: {
placeholder: '请输入'
}
},
{
name: 'field4',
label: '字段4', // (请求下拉数据)
type: 'select',
// rules: [{ required: true }],
options: selectOptions1,
props: {
placeholder: '请输入'
}
},
{
name: 'field5',
label: '字段5', // (请求下拉数据)
type: 'select',
// rules: [{ required: true }],
options: selectOptions2,
props: {
placeholder: '请输入'
}
},
{
name: 'field6',
label: '字段6',
type: 'inputnumber',
rules: [{ required: true }],
props: {
placeholder: '请输入',
}
},
{
type: 'custom',
name: 'field7',
render: (
<Form.Item key="form_key_field7" label="字段7">
<Form.Item
name="field7"
label="字段7"
noStyle
rules={[{ required: true }]}
>
<InputNumber min={1} max={10} />
</Form.Item>
<span className="sage-form-text"> machines</span>
</Form.Item>
)
},
{
type: 'custom',
name: 'field89',
render: (
<Form.Item key="form_key_field89" label="字段8和9">
<Input.Group compact>
<Form.Item
label='field8'
name={['field89', 'field8']}
noStyle
rules={[{ required: true }]}
>
<Select style={{ width: '50%' }} placeholder="请选择">
<Option value="Zhejiang">Zhejiang</Option>
<Option value="Jiangsu">Jiangsu</Option>
</Select>
</Form.Item>
<Form.Item
label='field9'
name={['field89', 'field9']}
noStyle
rules={[{ required: true }]}
>
<Input style={{ width: '50%' }} placeholder="请输入" />
</Form.Item>
</Input.Group>
</Form.Item>
)
},
{
type: 'custom',
name: 'field1011',
render: (
<Form.Item key="form_key_field1011" label="字段10和11" style={{ marginBottom: 0 }}>
<Form.Item
name="field10"
rules={[{ required: true, message: 'field10是必填项!' }]}
style={{ display: 'inline-block', width: 'calc(50% - 8px)' }}
>
<Input placeholder="请输入" />
</Form.Item>
<Form.Item
name="field11"
rules={[{ required: true, message: 'field11是必填项!' }]}
style={{ display: 'inline-block', width: 'calc(50% - 8px)', margin: '0 8px' }}
>
<Input placeholder="请输入" />
</Form.Item>
</Form.Item>
)
},
{
name: 'field12',
label: '字段12',
type: 'switch'
},
{
name: 'field13',
label: '字段13',
type: 'slider',
props: {
marks: {
0: 'A',
20: 'B',
40: 'C',
60: 'D',
80: 'E',
100: 'F',
}
}
},
{
name: 'field14',
label: '字段14',
type: 'radio',
options: [
{ value: 'a', text: 'A' },
{ value: 'b', text: 'B' },
{ value: 'c', text: 'C' },
{ value: 'd', text: 'D' }
]
},
{
name: 'field15',
label: '字段15',
type: 'checkbox',
options: [
{ value: 'a', label: 'A' },
{ value: 'b', label: 'B' },
{ value: 'c', label: 'C' },
{ value: 'd', label: 'D' }
]
},
{
name: 'field16',
label: '字段16',
type: 'rate'
},
{
name: 'field17',
label: '字段17',
type: 'treeselect',
rules: [{ required: true }],
props: {
placeholder: '请选择',
treeData: [
{ title: 'Light', value: 'light', children: [{ title: 'Bamboo', value: 'bamboo' }] }
]
}
},
{
name: 'field18',
label: '字段18',
type: 'cascader',
rules: [{ required: true }],
props: {
options: [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},
]
}
},
{
name: 'field19',
label: '字段19',
type: 'datepicker',
rules: [{ required: true }],
props: {
style: { width: '100%' }
}
},
{
name: 'field20',
label: '字段20',
type: 'autocomplete',
rules: [{ required: true }],
props: {
placeholder: '请输入',
options: [
{ value: 'Burns Bay Road' },
{ value: 'Downing Street' },
{ value: 'Wall Street' }
]
}
},
{
name: 'field21',
label: '字段21',
type: 'autocomplete',
rules: [{ required: true }],
children: (
<>
<AutoComplete.Option key="1" value="value1">value1</AutoComplete.Option>
<AutoComplete.Option key="2" value="value2">value2</AutoComplete.Option>
<AutoComplete.Option key="3" value="value3">value3</AutoComplete.Option>
</>
),
props: {
placeholder: '请输入'
}
},
{
name: 'field22',
label: '字段22',
type: 'datepicker',
rules: [{ required: true }],
props: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
style: { width: '100%' }
}
},
{
name: 'field23',
label: '字段23',
type: 'monthpicker',
rules: [{ required: true }]
},
{
name: 'field24',
label: '字段24',
type: 'rangepicker',
rules: [{ required: true }],
props: {
style: { width: '100%' }
}
},
{
name: 'field25',
label: '字段25',
type: 'timepicker',
rules: [{ required: true }],
props: {
style: { width: '100%' }
}
},
{
name: 'field26',
label: '字段26',
type: 'simplepictureupload',
rules: [{ required: true }],
props: {
uploadSuccess
},
},
{
name: 'field27',
label: '字段27',
type: 'multiplepictureupload',
rules: [{ required: true }],
maxNum: 2,
props: {
uploadSuccess
},
},
{
name: 'field28',
label: '字段28',
type: 'normalupload',
maxNum: 2,
rules: [{ required: true }],
props: {
listType: 'picture',
uploadSuccess
},
},
]
return (
<SageCard title="新增">
<Spin spinning={loading} tip="提交中">
<SageForm
ref={formRef}
formFields={formFields}
labelCol={ {span: 3 }}
wrapperCol={ {span: 9} }
onFinish={onFinish}
onFinishFailed={onFinishFailed}
onReturn={onReturn}
showButtonRow
showSubmitButton
showReturnButton
tailLayout={{
wrapperCol: { offset: 3, span: 9 }
}}
/>
</Spin>
</SageCard>
)
}
export default connect(({ global }) => ({
global
}))(CreateForm)
import React, { useState, useRef, useEffect } from 'react'
import { Form, Input, InputNumber, Select, AutoComplete, Spin } from 'antd'
import { connect, dropByCacheKey } from 'umi'
import moment from 'moment'
import { SageCard, SageForm, SageMessage } from '@/components/Common'
import { getEnumDropDownList } from '@/services/enum'
import { requestPrefix } from '@/services/prefix'
import { updateCrud, getCrudDetail } from '../service';
const { Option } = Select
const UpdateForm = (props) => {
const { location } = props
const formRef = useRef()
// 初始化数据
const [detail, setDetail] = useState({})
const [loading, setLoading] = useState(false)
const [tip, setTip] = useState('加载中...')
const [selectOptions1, setSelectOptions1] = useState([])
const [selectOptions2, setSelectOptions2] = useState([])
// 初始化下拉数据
const initSelectOptions = async () => {
const res = await getEnumDropDownList({
code: 'DEVICE_CONTROL_TYPE,DEVICE_FUNCTION_TYPE'
})
if (res.isSuccess) {
const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data
DEVICE_CONTROL_TYPE && DEVICE_CONTROL_TYPE.forEach(item => {
item.text = item.dictValue
item.value = item.dictKey
})
DEVICE_FUNCTION_TYPE && DEVICE_FUNCTION_TYPE.forEach(item => {
item.text = item.dictValue
item.value = item.dictKey
})
setSelectOptions1(DEVICE_CONTROL_TYPE || [])
setSelectOptions2(DEVICE_FUNCTION_TYPE || [])
}
}
const getDetail = async () => {
setLoading(true)
const res = await getCrudDetail({ id: location.query.id })
setLoading(false)
if (res.isSuccess) {
const { data } = res
setDetail(data)
formRef.current.setFieldsValue({
field1: data.field1,
field2: data.field2,
field3: data.field3,
field4: data.field4,
field5: data.field5,
field6: data.field6,
field7: data.field7,
field89: {
field8: data.field8,
field9: data.field9
},
field10: data.field10,
field11: data.field11,
field12: data.field12 === '1',
field13: data.field13,
field14: data.field14,
field15: data.field15 ? JSON.parse(data.field15) : [],
field16: data.field16 ? Number(data.field16) : 0,
field17: data.field17,
field18: data.field18 ? JSON.parse(data.field18) : [],
field19: data.field19 ? moment(data.field19) : '',
field20: data.field20,
field21: data.field21,
field22: data.field22 ? moment(data.field22) : '',
field23: data.field23 ? moment(data.field23) : '',
field24: data.field24 ? [moment(JSON.parse(data.field24)[0]), moment(JSON.parse(data.field24)[1])] : '',
field25: data.field25 ? moment(data.field25, 'HH:mm:ss') : '',
field26: data.field26,
field27: data.field27 ? JSON.parse(data.field27) : [],
field28: data.field28 ? JSON.parse(data.field28) : [],
})
}
}
useEffect(() => {
initSelectOptions()
getDetail()
}, [])
// 上传成功
const uploadSuccess = (field, value) => {
formRef.current.setFieldsValue({ [field]: value })
}
// 返回
const onReturn = () => {
props.dispatch({
type: 'global/returnTab',
payload: {
closePath: location.pathname,
returnPath: '/demo/tabcrud',
returnName: 'TabCrud'
}
})
}
const onFinish = async (values) => {
const formData = Object.assign({}, values)
console.log('提交数据:', formData)
// 处理赋值表单数据
formData.field1 = '字段1的值'
// 多字段
formData.field8 = values.field89.field8
formData.field9 = values.field89.field9
delete formData.field89
// 开关
formData.field12 = values.field12 ? '1' : '0'
// 时间
formData.field19 = values.field19 ? values.field19.format('YYYY-MM-DD') : ''
formData.field22 = values.field22 ? values.field22.format('YYYY-MM-DD HH:mm:ss') : ''
formData.field23 = values.field23 ? values.field23.format('YYYY-MM') : ''
formData.field24 = values.field24 ? [values.field24[0].format('YYYY-MM-DD'), values.field24[1].format('YYYY-MM-DD')] : []
formData.field25 = values.field25 ? values.field25.format('HH:mm:ss') : ''
formData.id = detail.id
setTip('提交中...')
setLoading(true)
const res = await updateCrud(formData)
setLoading(false)
if (res.isSuccess) {
SageMessage.success('保存成功')
dropByCacheKey('/demo/tabcrud')
onReturn()
}
}
// 获取图片列表
const getFileList = (list) => {
const imageList = list ? JSON.parse(list) : []
const fileList = []
imageList.forEach(item => {
const obj = {}
obj.id = item
obj.uid = Math.random()
obj.name = item
obj.status = 'done'
obj.url = `/${requestPrefix}/sys/file/showImage?imageId=${item}`
fileList.push(obj)
})
return fileList
}
// 表单字段设置
const formFields = [
{
name: 'field1',
label: '字段1',
type: 'text',
props: {
value: '字段1的值'
}
},
{
name: 'field2',
label: '字段2',
type: 'input',
rules: [{ required: true }],
props: {
placeholder: '请输入'
}
},
{
name: 'field3',
label: '字段3', // (固定下拉数据)
type: 'select',
rules: [{ required: true }],
options: [
{ text: '选项1', value: 'select1' },
{ text: '选项2', value: 'select2' }
],
props: {
placeholder: '请输入'
}
},
{
name: 'field4',
label: '字段4', // (请求下拉数据)
type: 'select',
// rules: [{ required: true }],
options: selectOptions1,
props: {
placeholder: '请输入'
}
},
{
name: 'field5',
label: '字段5', // (请求下拉数据)
type: 'select',
// rules: [{ required: true }],
options: selectOptions2,
props: {
placeholder: '请输入'
}
},
{
name: 'field6',
label: '字段6',
type: 'inputnumber',
rules: [{ required: true }],
props: {
placeholder: '请输入',
}
},
{
name: 'field7',
type: 'custom',
render: (
<Form.Item key="form_key_field7" label="字段7">
<Form.Item
name="field7"
label="字段7"
noStyle
rules={[{ required: true }]}
>
<InputNumber min={1} max={10} />
</Form.Item>
<span className="sage-form-text"> machines</span>
</Form.Item>
)
},
{
name: 'field89',
type: 'custom',
render: (
<Form.Item key="form_key_field89" label="字段8和9">
<Input.Group compact>
<Form.Item
label='field8'
name={['field89', 'field8']}
noStyle
rules={[{ required: true }]}
>
<Select style={{ width: '50%' }} placeholder="请选择">
<Option value="Zhejiang">Zhejiang</Option>
<Option value="Jiangsu">Jiangsu</Option>
</Select>
</Form.Item>
<Form.Item
label='field9'
name={['field89', 'field9']}
noStyle
rules={[{ required: true }]}
>
<Input style={{ width: '50%' }} placeholder="请输入" />
</Form.Item>
</Input.Group>
</Form.Item>
)
},
{
name: 'field1011',
type: 'custom',
render: (
<Form.Item key="form_key_field1011" label="字段10和11" style={{ marginBottom: 0 }}>
<Form.Item
name="field10"
rules={[{ required: true, message: 'field10是必填项!' }]}
style={{ display: 'inline-block', width: 'calc(50% - 8px)' }}
>
<Input placeholder="请输入" />
</Form.Item>
<Form.Item
name="field11"
rules={[{ required: true, message: 'field11是必填项!' }]}
style={{ display: 'inline-block', width: 'calc(50% - 8px)', margin: '0 8px' }}
>
<Input placeholder="请输入" />
</Form.Item>
</Form.Item>
)
},
{
name: 'field12',
label: '字段12',
type: 'switch'
},
{
name: 'field13',
label: '字段13',
type: 'slider',
props: {
marks: {
0: 'A',
20: 'B',
40: 'C',
60: 'D',
80: 'E',
100: 'F',
}
}
},
{
name: 'field14',
label: '字段14',
type: 'radio',
options: [
{ value: 'a', text: 'A' },
{ value: 'b', text: 'B' },
{ value: 'c', text: 'C' },
{ value: 'd', text: 'D' }
]
},
{
name: 'field15',
label: '字段15',
type: 'checkbox',
options: [
{ value: 'a', label: 'A' },
{ value: 'b', label: 'B' },
{ value: 'c', label: 'C' },
{ value: 'd', label: 'D' }
]
},
{
name: 'field16',
label: '字段16',
type: 'rate'
},
{
name: 'field17',
label: '字段17',
type: 'treeselect',
rules: [{ required: true }],
props: {
treeData: [
{ title: 'Light', value: 'light', children: [{ title: 'Bamboo', value: 'bamboo' }] }
]
}
},
{
name: 'field18',
label: '字段18',
type: 'cascader',
rules: [{ required: true }],
props: {
options: [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},
]
}
},
{
name: 'field19',
label: '字段19',
type: 'datepicker',
rules: [{ required: true }],
props: {
style: { width: '100%' }
}
},
{
name: 'field20',
label: '字段20',
type: 'autocomplete',
rules: [{ required: true }],
props: {
placeholder: '请输入',
options: [
{ value: 'Burns Bay Road' },
{ value: 'Downing Street' },
{ value: 'Wall Street' }
]
}
},
{
name: 'field21',
label: '字段21',
type: 'autocomplete',
rules: [{ required: true }],
children: (
<>
<AutoComplete.Option key="1" value="value1">value1</AutoComplete.Option>
<AutoComplete.Option key="2" value="value2">value2</AutoComplete.Option>
<AutoComplete.Option key="3" value="value3">value3</AutoComplete.Option>
</>
),
props: {
placeholder: '请输入'
}
},
{
name: 'field22',
label: '字段22',
type: 'datepicker',
rules: [{ required: true }],
props: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
style: { width: '100%' }
}
},
{
name: 'field23',
label: '字段23',
type: 'monthpicker',
rules: [{ required: true }]
},
{
name: 'field24',
label: '字段24',
type: 'rangepicker',
rules: [{ required: true }],
props: {
style: { width: '100%' }
}
},
{
name: 'field25',
label: '字段25',
type: 'timepicker',
rules: [{ required: true }],
props: {
style: { width: '100%' }
}
},
{
name: 'field26',
label: '字段26',
type: 'simplepictureupload',
rules: [{ required: true }],
props: {
previewImage: `/${requestPrefix}/sys/file/showImage?imageId=${detail.field26}`,
uploadSuccess
},
},
{
name: 'field27',
label: '字段27',
type: 'multiplepictureupload',
rules: [{ required: true }],
maxNum: 2,
props: {
fileList: getFileList(detail.field27),
uploadSuccess
},
},
{
name: 'field28',
label: '字段28',
type: 'normalupload',
maxNum: 2,
rules: [{ required: true }],
props: {
listType: 'picture',
fileList: getFileList(detail.field28),
uploadSuccess
},
},
]
return (
<SageCard title="编辑">
<Spin spinning={loading} tip={tip}>
<SageForm
ref={formRef}
formFields={formFields}
labelCol={ {span: 3 }}
wrapperCol={ {span: 9} }
// initialValues={detail}
onFinish={onFinish}
onReturn={onReturn}
showButtonRow
showSubmitButton
showReturnButton
tailLayout={{
wrapperCol: { offset: 3, span: 9 }
}}
/>
</Spin>
</SageCard>
)
}
export default connect(({ global }) => ({
global
}))(UpdateForm)
import React, { useState, useEffect, useRef } from 'react'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import { connect, dropByCacheKey } from 'umi'
import { SageTable, SageButton, SageMessage, ActionSet } from '@/components/Common'
import { PlusOutlined, EditOutlined, DeleteOutlined, VerticalAlignBottomOutlined, VerticalAlignTopOutlined } from '@ant-design/icons';
import moment from 'moment';
import { queryCrud, updateCrud, removeCrud, getCrudDetail } from './service';
// 详情数据
const initDetail = {
id: null
}
const CrudList = (props) => {
// 状态数据
const [detail, setDetail] = useState(initDetail) // 详情
const [editable, setEditable] = useState(true) // 编辑按钮状态
const [removeable, setRemoveable] = useState(true) // 删除按钮状态
// ref对象
const tableRef = useRef();
const modalRef = useRef();
const updateFormRef = useRef();
useEffect(() => {
}, [])
// 查询条件
const searchFields = [
{
name: 'field2',
label: '字段2',
type: 'input',
props: {
placeholder: '请输入'
}
},
{
name: 'field3',
label: '字段3', // (固定下拉数据)
type: 'select',
options: [
{ text: '选项1', value: 'select1' },
{ text: '选项2', value: 'select2' }
],
props: {
placeholder: '请输入',
allowClear: true
}
}
]
// 查询
const onSearchTable = (params) => {
if (tableRef.current) {
const postParams = Object.assign({ pageNum: 1 }, params)
// 处理查询条件
tableRef.current.queryTable(postParams)
}
}
// 重置
const onResetTable = () => {
if (tableRef.current) {
tableRef.current.queryTable({ pageNum: 1 }, 'reset')
}
}
const tableSearchFormProps = {
searchFields,
onSearchTable,
onResetTable
}
// 编辑
const handleEdit = async (event, record) => {
event.stopPropagation()
dropByCacheKey('/demo/tabcrud/edit')
props.dispatch({
type: 'global/goTab',
payload: {
path: `/demo/tabcrud/edit`,
name: '编辑Crud',
query: {
id: record.id
}
}
})
}
// 删除
const handleDelete = async (event, record) => {
event.stopPropagation()
const res = await removeCrud({ idArr: [record.id] })
if (res.isSuccess) {
SageMessage.success('删除成功')
tableRef.current.reloadTable()
}
}
// 表格
const columns = [
{
title: '字段1',
dataIndex: 'field1',
key: 'field1',
width: 200,
},
{
title: '字段2',
dataIndex: 'field2',
key: 'field2',
width: 200,
sortField: 't1.field2',
sorter: true
},
{
title: '字段3',
dataIndex: 'field3',
key: 'field3',
width: 200,
},
{
title: '字段4',
dataIndex: 'field4',
key: 'field4',
width: 200,
},
{
title: '字段5',
dataIndex: 'field5',
key: 'field5',
width: 200,
},
{
title: '字段6',
dataIndex: 'field6',
key: 'field6',
width: 200,
},
{
title: '字段7',
dataIndex: 'field7',
key: 'field7',
width: 200,
},
{
title: '字段8',
dataIndex: 'field8',
key: 'field8',
width: 200,
},
{
title: '字段9',
dataIndex: 'field9',
key: 'field9',
width: 200,
},
{
title: '字段10',
dataIndex: 'field10',
key: 'field10',
width: 200,
},
{
title: '字段11',
dataIndex: 'field11',
key: 'field11',
width: 200,
},
{
title: '字段12',
dataIndex: 'field12',
key: 'field12',
width: 200,
},
{
title: '字段13',
dataIndex: 'field13',
key: 'field13',
width: 200,
},
{
title: '字段14',
dataIndex: 'field14',
key: 'field14',
width: 200,
},
{
title: '字段15',
dataIndex: 'field15',
key: 'field15',
width: 200,
},
{
title: '字段16',
dataIndex: 'field16',
key: 'field16',
width: 200,
},
{
title: '字段17',
dataIndex: 'field17',
key: 'field17',
width: 200,
},
{
title: '字段18',
dataIndex: 'field18',
key: 'field18',
width: 300,
},
{
title: '字段19',
dataIndex: 'field19',
key: 'field19',
width: 200,
},
{
title: '字段20',
dataIndex: 'field20',
key: 'field20',
width: 200,
},
{
title: '字段21',
dataIndex: 'field21',
key: 'field21',
width: 200,
},
{
title: '字段22',
dataIndex: 'field22',
key: 'field22',
width: 200,
},
{
title: '字段23',
dataIndex: 'field23',
key: 'field23',
width: 200,
},
{
title: '字段24',
dataIndex: 'field24',
key: 'field24',
width: 300,
},
{
title: '字段25',
dataIndex: 'field25',
key: 'field25',
width: 200,
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
width: 200,
sortField: 't1.created_At',
sorter: true
},
{
title: '操作',
fixed: 'right',
dataIndex: 'button',
key: 'action',
align: 'center',
render: (button, record) => {
const actionList = [
{ title: '编辑', method: (e) => handleEdit(e, record) },
{ title: '删除', method: (e) => handleDelete(e, record), isConfirm: true, confirmInfo: '确认删除该角色?' },
]
return <ActionSet actionList={actionList} record={record} />
},
width: 120
}
]
const tableProps = {
rowKey: 'id',
hasNumber: true,
hasCheck: true,
columns,
scroll: { x: '100vw' },
rowSelection: {
onChange: (selectedrowkeys, selectedrows) => {
tableRef.current.setSelectedRowKeys(selectedrowkeys)
tableRef.current.setSelectedRows(selectedrows)
setEditable(selectedrowkeys.length !== 1)
setRemoveable(selectedrowkeys.length === 0)
}
}
}
// 新建按钮
const onAdd = () => {
props.dispatch({
type: 'global/goTab',
payload: {
path: '/demo/tabcrud/add',
name: '新增Crud'
}
})
}
// 编辑按钮
const onEdit = (e) => {
const rowRecords = tableRef.current.getSelectedRows()
handleEdit(e, rowRecords[0])
}
// 删除按钮
const onDelete = async (e) => {
e.stopPropagation()
const rowRecords = tableRef.current.getSelectedRowKeys()
const res = await removeCrud({ idArr: rowRecords })
if (res.isSuccess) {
SageMessage.success('删除成功')
tableRef.current.reloadTable()
}
}
// 导入按钮
const onImport = (e) => {
alert('待实现')
}
// 导出按钮
const onExport = (e) => {
alert('待实现')
}
// 表格按钮操作
const tableToolProps = {
toolBarRender: () => {
return (
<>
<SageButton type="primary" icon={<PlusOutlined />} onClick={onAdd}>新增</SageButton>
<SageButton type="success" icon={<EditOutlined />} onClick={(e) => onEdit(e)} disabled={editable} style={{marginLeft: '8px'}}>编辑</SageButton>
<SageButton type="danger" icon={<DeleteOutlined />} onClick={(e) => onDelete(e)} disabled={removeable} style={{marginLeft: '8px'}}>删除</SageButton>
<SageButton type="warning" icon={<VerticalAlignBottomOutlined />} onClick={(e) => onImport(e)} style={{marginLeft: '8px'}}>导入</SageButton>
<SageButton type="warning" icon={<VerticalAlignTopOutlined />} onClick={(e) => onExport(e)} style={{marginLeft: '8px'}}>导出</SageButton>
</>
)
},
toolOptionConfig: ['reload', 'hiddensearch', 'density', 'fullScreen']
}
return (
<PageHeaderWrapper>
<SageTable
ref={tableRef}
{...tableSearchFormProps}
{...tableToolProps}
{...tableProps}
request={(params) => queryCrud(params)}
/>
</PageHeaderWrapper>
)
}
export default connect(({ global }) => ({
global
}))(CrudList)
import request from '@/utils/request';
import { requestPrefix } from '@/services/prefix'
export async function queryCrud(params) {
return request(`/${requestPrefix}/party/test/queryList`, {
method: 'POST',
data: { ...params },
});
}
export async function removeCrud(params) {
return request(`/${requestPrefix}/party/test/deleteBatch`, {
method: 'POST',
data: { ...params },
});
}
export async function addCrud(params) {
return request(`/${requestPrefix}/party/test/saveOrEdit`, {
method: 'POST',
data: { ...params },
});
}
export async function updateCrud(params) {
return request(`/${requestPrefix}/party/test/saveOrEdit`, {
method: 'POST',
data: { ...params },
});
}
// 查询
export function getCrudDetail(params) {
return request(`/${requestPrefix}/party/test/selectById`, {
method: 'POST',
data: { ...params },
})
}
import React, { useState, useEffect, useRef } from 'react' import React, { useState, useEffect, useRef } from 'react'
import { PageHeaderWrapper } from '@ant-design/pro-layout' import { PageHeaderWrapper } from '@ant-design/pro-layout'
import { connect } from 'umi'
import { SageTable, SageModal, SageButton, SageMessage, ActionSet } from '@/components/Common' import { SageTable, SageModal, SageButton, SageMessage, ActionSet } from '@/components/Common'
import { createFromIconfontCN, PlusOutlined, EditOutlined, ReloadOutlined, SwapOutlined, DeleteOutlined, VerticalAlignBottomOutlined, VerticalAlignTopOutlined } from '@ant-design/icons'; import { createFromIconfontCN, PlusOutlined, EditOutlined, ReloadOutlined, SwapOutlined, DeleteOutlined, VerticalAlignBottomOutlined, VerticalAlignTopOutlined } from '@ant-design/icons';
import moment from 'moment';
import config from '@/config'
import { getEnumDropDownList } from '@/services/enum'
import { queryMenu, updateMenu, addMenu, removeMenu, getMenuDetail, clearMenu } from './service'; import { queryMenu, updateMenu, addMenu, removeMenu, getMenuDetail, clearMenu } from './service';
import CreateForm from './components/CreateForm' import CreateForm from './components/CreateForm'
import UpdateForm from './components/UpdateForm' import UpdateForm from './components/UpdateForm'
const IconFont = createFromIconfontCN({
scriptUrl: config.IconUrl,
});
// 详情数据 // 详情数据
const initDetail = { const initDetail = {
id: null id: null
} }
const MenuList = () => { const MenuList = (props) => {
const { settings } = props
// 状态数据 // 状态数据
const [detail, setDetail] = useState(initDetail) // 详情 const [detail, setDetail] = useState(initDetail) // 详情
...@@ -33,6 +30,10 @@ const MenuList = () => { ...@@ -33,6 +30,10 @@ const MenuList = () => {
const createFormRef = useRef(); const createFormRef = useRef();
const updateFormRef = useRef(); const updateFormRef = useRef();
const IconFont = createFromIconfontCN({
scriptUrl: settings.iconfontUrl,
});
useEffect(() => { useEffect(() => {
}, []) }, [])
...@@ -382,4 +383,6 @@ const MenuList = () => { ...@@ -382,4 +383,6 @@ const MenuList = () => {
) )
} }
export default MenuList export default connect(({ settings }) => ({
settings,
}))(MenuList);
...@@ -218,6 +218,7 @@ const Center = (props) => { ...@@ -218,6 +218,7 @@ const Center = (props) => {
formFields={formFields} formFields={formFields}
onFinish={onFinish} onFinish={onFinish}
onFinishFailed={onFinishFailed} onFinishFailed={onFinishFailed}
showButtonRow
showSubmitButton showSubmitButton
tailLayout={{ tailLayout={{
wrapperCol: { offset: 3, span: 21 } wrapperCol: { offset: 3, span: 21 }
...@@ -232,6 +233,7 @@ const Center = (props) => { ...@@ -232,6 +233,7 @@ const Center = (props) => {
formFields={formFields2} formFields={formFields2}
onFinish={onFinish2} onFinish={onFinish2}
onFinishFailed={onFinishFailed2} onFinishFailed={onFinishFailed2}
showButtonRow
showSubmitButton showSubmitButton
tailLayout={{ tailLayout={{
wrapperCol: { offset: 3, span: 21 } wrapperCol: { offset: 3, span: 21 }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论