From fa71559c92ce8f7429971370ca4bd1139c903621 Mon Sep 17 00:00:00 2001 From: Mr Ke <kelq@hugeinfo.com.cn> Date: Wed, 27 May 2020 11:16:05 +0800 Subject: [PATCH] oa+用户中心 --- src/components/oa/index/rulesList/index.jsx | 0 src/module/login/login.jsx | 20 src/components/common/HeadView/index.scss | 11 src/module/oa/logManage/operLog.jsx | 2 src/module/huge-base/FunctionManage.jsx | 327 +++ src/components/common/TopListTableView/tagList.js | 100 src/components/oa/DocumentDetailPage/index.jsx | 0 src/components/oa/personal/information/index.jsx | 0 src/components/oa/personal/information/index.scss | 0 src/components/oa/DocumentEditPage/index.jsx | 0 src/module/huge-base/JobDetail.jsx | 122 + src/components/oa/DocumentDetailPage/index.scss | 0 src/components/oa/logManage/Rawler/index.jsx | 0 src/module/huge-base/Menu.jsx | 51 src/module/huge-base/UnitDetailEdit.jsx | 167 + src/routeDom/oaRouteDom.jsx | 42 src/components/oa/logManage/Rawler/index.scss | 0 src/module/huge-base/HeaderCustom.jsx | 18 src/module/oa/index/Announcement.jsx | 4 src/api/httpurl.js | 4 src/components/oa/logManage/operLog/index.scss | 0 src/module/login/login.scss | 0 src/module/oa/index/System.jsx | 4 build(修复日期显示).zip | 0 src/module/huge-base/AppServiceManage.jsx | 113 + src/module/huge-base/RoleManage.jsx | 114 + src/module/huge-base/GroupManage.jsx | 121 + src/components/common/SearchFormView/index.jsx | 8 src/components/oa/index/rulesList/index.scss | 0 src/module/huge-base/ActivitiImg.jsx | 33 src/components/oa/basicConfig/UserManage.jsx | 2 src/module/huge-base/UserDetail.jsx | 444 ++++ src/components/oa/DocumentEditPage/index.scss | 0 src/components/oa/index/workbench/index.jsx | 0 src/components/oa/logManage/browseLog/index.scss | 0 src/module/oa/document/DocumentEdit.jsx | 4 src/module/huge-base/DeptDetail.jsx | 99 + src/components/oa/basicConfig/UserDetail.jsx | 0 src/module/huge-base/UserManage.jsx | 139 + src/module/huge-base/RoleDetail.jsx | 187 + src/module/huge-base/GroupDetail.jsx | 150 + src/module/oa/index/workbench.jsx | 61 src/module/oa/logManage/browseLog.jsx | 2 src/module/huge-base/UnitManage.jsx | 252 ++ src/components/oa/AnnouncementPage/index.scss | 0 src/module/oa/document/DocumentDetail.jsx | 4 src/module/huge-base/AppServiceDetail.jsx | 143 + src/components/common/TopListTableView/index.jsx | 10 src/module/huge-base/ActivitiDetail.jsx | 98 + src/components/oa/index/workbench/index.scss | 0 src/module/huge-base/AuthorityManage.jsx | 267 ++ src/index.css | 64 src/module/huge-base/JobManage.jsx | 566 +++++ src/module/huge-base/DepartmentManage.jsx | 316 +++ src/module/huge-base/FunctionDetail.jsx | 104 + src/routeDom/userRouteDom.jsx | 47 src/module/oa/logManage/Rawler.jsx | 2 src/module/menu/menu.jsx | 81 src/index.js | 162 src/api/request.js | 23 src/module/huge-base/ModuleDetailEdit.jsx | 209 ++ src/module/huge-base/DeployManage.jsx | 245 ++ src/components/oa/AnnouncementPage/index.jsx | 0 src/menu/index.js | 3 src/menu/menu.user.js | 88 src/module/huge-base/ModulesManage.jsx | 314 +++ src/components/common/Tree/index.jsx | 210 ++ src/components/oa/logManage/browseLog/index.jsx | 0 src/module/oa/personal/information.jsx | 2 /dev/null | 81 src/components/common/HeadView/index.jsx | 84 src/style/reset.scss | 6 src/components/oa/logManage/operLog/index.jsx | 0 src/components/common/NotifyList/index.jsx | 2 src/menu/menu.oa.js | 73 75 files changed, 5,544 insertions(+), 261 deletions(-) diff --git "a/build\050\344\277\256\345\244\215\346\227\245\346\234\237\346\230\276\347\244\272\051.zip" "b/build\050\344\277\256\345\244\215\346\227\245\346\234\237\346\230\276\347\244\272\051.zip" new file mode 100644 index 0000000..008e32a --- /dev/null +++ "b/build\050\344\277\256\345\244\215\346\227\245\346\234\237\346\230\276\347\244\272\051.zip" Binary files differ diff --git a/src/api/httpurl.js b/src/api/httpurl.js index 5285521..bc312c0 100644 --- a/src/api/httpurl.js +++ b/src/api/httpurl.js @@ -1,7 +1,7 @@ //内网测试地址 -// let StagingUrl = 'http://192.168.0.116:9072'; +// let StagingUrl = 'http://192.168.0.106:9072'; let StagingUrl = "http://120.79.193.119:9072"; - +// let StagingUrl = "http://120.79.193.119:9075"; //mock地址 let MockUrl = 'http://localhost:3721/'; diff --git a/src/api/request.js b/src/api/request.js index 2228239..5d6752d 100644 --- a/src/api/request.js +++ b/src/api/request.js @@ -32,7 +32,7 @@ method = 'get', showToast = true, autoLogin = true, - headers = {} + headers = {}, } = options; let token = window.localStorage.getItem('token') || undefined; @@ -50,9 +50,9 @@ method, data, params, - headers + headers, }) - .then(res => { + .then((res) => { // Taro.hideLoading(); const { code, data, msg } = res.data; if (code == '0') { @@ -64,24 +64,15 @@ code == '10003' ) { // token失效重新返回登录页面 - this.props.history.push({ pathname: '/login' }); + // this.props.history.push({ pathname: '/login' }); + window.location.href = window.location.origin + '#/login'; } else { message.warning(msg); return false; } }) - .catch(err => { + .catch((err) => { console.log(err); - let defaultMsg = ''; - - if (err.code !== CODE_SUCCESS) { - defaultMsg = '请求异常,请检查网络连接状况'; - } - // Taro.showToast({ - // title: defaultMsg, - // icon: "none" - // }); - // return Promise.reject({ message: defaultMsg, ...err }); - return Promise.reject({ msg: 'error' }); + window.location.href = window.location.origin + '#/login'; }); } diff --git a/src/components/common/HeadView/index.jsx b/src/components/common/HeadView/index.jsx index e40d599..899d80b 100644 --- a/src/components/common/HeadView/index.jsx +++ b/src/components/common/HeadView/index.jsx @@ -6,11 +6,17 @@ /** 头部组件 */ -import React, { useEffect } from 'react'; -import { Layout, Menu, Dropdown, Icon, Row, Col, message } from 'antd'; +import React, { useEffect, useState, useContext } from 'react'; +import { Layout, Menu, Dropdown, Icon, Row, Col, message, Select } from 'antd'; +import { createHashHistory } from 'history'; const { Header } = Layout; +import logo from '../../../img/logo.png' import './index.scss'; +import { Context } from '../../../index'; +const history = createHashHistory(); + +const { Option } = Select; const menu = ( <Menu> <Menu.Item> @@ -24,30 +30,70 @@ 退出 </a> </Menu.Item> - </Menu> ); -export default function MenuView({ }) { - +export default function HeadView({ props }) { var loginUser = window.localStorage.getItem('loginUser') || '{}'; loginUser = JSON.parse(loginUser); - + + const [selectList, setSelectList] = useState([{ name: 'OA系统', key: 'oa' }]); + // const [selectKey, setSelectKey] = useState('oa'); + + useEffect(() => { + // 获取该登录用户的菜单权限 + let menu = window.localStorage.getItem('menu') ? JSON.parse(window.localStorage.getItem('menu')) : [];//获取权限菜单 + let administration = menu.find(({ moduleSymbol }) => moduleSymbol == 'administration'); + if (administration) { + setSelectList(selectList.concat({ name: '用户中心', key: 'user' })); + } + }, []) + + function onSelectChange(value) { + // setSelectKey(value); + // setContext && setContext({ value }) + } + return ( - <Header style={{ background: '#fff', padding: 0, boxShadow: 'inset 0 -1px 0 0 #E5E5E5' }}> + <Context.Consumer> { - (loginUser && Object.keys(loginUser).length) && - <Row type="flex" align="middle" justify="end" > - <Col style={{ marginRight: 40 }}> - {loginUser.trueName} - <Dropdown overlay={menu}> - <a className="ant-dropdown-link" onClick={e => e.preventDefault()}> - [{loginUser.dept} | {loginUser.post}]<Icon type="caret-down" /> - </a> - </Dropdown> - </Col> - </Row> + ({ role, setContext }) => ( + <Header style={{ background: '#fff', padding: 0 }} className="header-view-main"> + <Row type="flex"> + <Col className="header-view-main-logo-area"> + <img src={logo} alt="恒巨科技" /> + </Col> + <Col className="flex-1"> + { + (loginUser && Object.keys(loginUser).length) && + <Row type="flex" align="middle" justify="space-between" > + <Col> + <Select value={role} size="small" style={{ marginLeft: 20, width: 120 }} onChange={value => { + setContext({ role: value }); + history.push('/') + }}> + { + selectList.map(({ name, key }) => ( + <Option value={key} key={key}>{name}</Option> + )) + } + </Select> + </Col> + <Col style={{ marginRight: 40 }}> + {loginUser.trueName} + <Dropdown overlay={menu}> + <a className="ant-dropdown-link" onClick={e => e.preventDefault()}> + [{loginUser.dept} | {loginUser.post}]<Icon type="caret-down" /> + </a> + </Dropdown> + </Col> + </Row> + } + </Col> + </Row> + </Header> + ) } - </Header> + </Context.Consumer> ); } diff --git a/src/components/common/HeadView/index.scss b/src/components/common/HeadView/index.scss index 5b152f5..7ee8b46 100644 --- a/src/components/common/HeadView/index.scss +++ b/src/components/common/HeadView/index.scss @@ -1,5 +1,12 @@ -.menu-view { +.header-view { &-main { - padding: 8px; + &-logo-area{ + width: 200px; + padding: 0 10px; + height: 100%; + & img{ + width: 100%; + } + } } } diff --git a/src/components/common/NotifyList/index.jsx b/src/components/common/NotifyList/index.jsx index 7409e23..b6afd7d 100644 --- a/src/components/common/NotifyList/index.jsx +++ b/src/components/common/NotifyList/index.jsx @@ -66,7 +66,7 @@ <marquee onMouseOut={this.onMouseOut} onMouseOver={this.onMouseOver} ref='marquee' style={{ cursor: 'pointer' }}>{notice.documentTitle || ''}</marquee> </div> { - notice.documentContent ? <Tooltip placement='topLeft' title={this.emoveTAG(notice.documentContent)} arrowPointAtCenter> + notice.documentContent ? <Tooltip placement='topLeft' title={this.emoveTAG(notice.documentContent)}> <div className="notify-list-main-dom-msg-content" onClick={() => { notice.id && this.linkDetail(notice.id) }}>{this.emoveTAG(notice.documentContent)}</div> </Tooltip> : null } diff --git a/src/components/common/SearchFormView/index.jsx b/src/components/common/SearchFormView/index.jsx index 398649e..bbc7bc1 100644 --- a/src/components/common/SearchFormView/index.jsx +++ b/src/components/common/SearchFormView/index.jsx @@ -107,7 +107,7 @@ }; render() { - const { formData = {}, data = [], children } = this.props; + const { formData = {}, data = [], children, width = "25%" } = this.props; let size = 'default'; return ( @@ -117,7 +117,7 @@ {data.length > 0 && data.map((item, idx) => ( - <Card.Grid key={idx} style={{ width: '20%' }} hoverable={false} > + <Card.Grid key={idx} style={{ width }} hoverable={false} > {(() => { switch (item.type) { case 'select': @@ -171,7 +171,7 @@ return ( <Form.Item label={item.label}> <RangePicker - style={{ width: '100%'}} + style={{ width: '100%' }} size={size} ranges={{ Today: [moment(), moment()], @@ -211,7 +211,7 @@ })()} </Card.Grid> ))} - <Card.Grid style={{ width: '20%' }}> + <Card.Grid style={{ width }}> <Row type="flex" gutter={20} align="middle" align="middle" style={{ height: 40 }}> <Col> <Button diff --git a/src/components/common/TopListTableView/index.jsx b/src/components/common/TopListTableView/index.jsx index edb1878..d607e53 100644 --- a/src/components/common/TopListTableView/index.jsx +++ b/src/components/common/TopListTableView/index.jsx @@ -31,7 +31,8 @@ this.setState({ topList: [ { ...tag['latenessRanking'], dataSource: res['latenessRanking'] }, - { ...tag['meritsRanking'], dataSource: res['meritsRanking'] }, + { ...tag['earlyRanking'], dataSource: res['earlyRanking'] }, + // { ...tag['meritsRanking'], dataSource: res['meritsRanking'] }, { ...tag['defectRanking'], dataSource: res['defectRanking'] }, ] }) @@ -42,11 +43,12 @@ componentDidMount() { } renderDom = ({ name, columns, dataSource }) => { - return <div className="top-list-table-view-main-table"> + return <div className="top-list-table-view-main-table h-100"> <div className="top-list-table-view-main-table-title">{name} - <span className="top-list-table-view-main-table-title-fuc">查看</span> + {/* <span className="top-list-table-view-main-table-title-fuc">查看</span> */} </div> <Table + scroll={{ y: 130 }} dataSource={dataSource ? dataSource.map((a, idx) => ({ ...a, key: idx })) : []} columns={columns} size="small" @@ -63,7 +65,7 @@ <Row type="flex" gutter={12}> { topList.map((item, idx) => { - return <Col span={24 / 3} key={idx}>{this.renderDom(item)}</Col>; + return <Col span={24 / topList.length} key={idx} >{this.renderDom(item)}</Col>; }) } </Row> diff --git a/src/components/common/TopListTableView/tagList.js b/src/components/common/TopListTableView/tagList.js index 4de7ad2..3c19a47 100644 --- a/src/components/common/TopListTableView/tagList.js +++ b/src/components/common/TopListTableView/tagList.js @@ -1,4 +1,5 @@ /* eslint-disable */ +import moment from 'moment'; export const tag = { // 绩效排行 meritsRanking: { @@ -10,17 +11,17 @@ key: 'index', render: (item, cur, idx) => { return idx + 1; - } + }, }, { title: '姓名', dataIndex: 'userName', - key: 'userName' + key: 'userName', }, { title: '部门', dataIndex: 'userDeptName', - key: 'userDeptName' + key: 'userDeptName', }, { title: '绩效得分', @@ -28,9 +29,9 @@ key: 'meritsGrade', render: (cur, item) => { return cur + '分'; - } - } - ] + }, + }, + ], }, // 缺陷排行 @@ -43,17 +44,17 @@ key: 'index', render: (item, cur, idx) => { return idx + 1; - } + }, }, { title: '姓名', dataIndex: 'userName', - key: 'userName' + key: 'userName', }, { title: '部门', dataIndex: 'userDeptName', - key: 'userDeptName' + key: 'userDeptName', }, { title: '缺陷数', @@ -61,11 +62,12 @@ key: 'defectNumber', render: (cur, item) => { return cur + '个'; - } - } - ] + }, + }, + ], }, + //迟到排行 latenessRanking: { name: '考勤(迟到)榜单', columns: [ @@ -75,34 +77,84 @@ key: 'index', render: (item, cur, idx) => { return idx + 1; - } + }, }, { title: '姓名', dataIndex: 'userName', - key: 'userName' + key: 'userName', }, { title: '部门', dataIndex: 'userDeptName', - key: 'userDeptName' + key: 'userDeptName', + width: '25%', }, { title: '次数', - dataIndex: 'lateness', - key: 'lateness', + dataIndex: 'lateTimes', + key: 'lateTimes', render: (item, cur) => { return item + '次'; - } + }, }, { title: '时长(分)', - dataIndex: 'latenessTime', - key: 'latenessTime', + dataIndex: 'lateMinute', + key: 'lateMinute', render: (item, cur) => { return item + '分钟'; - } - } - ] - } + }, + }, + ], + }, + + //早到排行 + earlyRanking: { + name: '考勤(早到)榜单', + columns: [ + { + title: '名次', + dataIndex: 'index', + key: 'index', + render: (item, cur, idx) => { + return idx + 1; + }, + }, + { + title: '姓名', + dataIndex: 'userName', + key: 'userName', + }, + { + title: '部门', + dataIndex: 'userDeptName', + key: 'userDeptName', + width: '25%', + }, + { + title: '打卡时间', + dataIndex: 'onDutyUserCheckTime', + key: 'onDutyUserCheckTime', + className: 'fontSize12', + width: '25%', + render: (item, cur) => { + return ( + item && + // <div style={{ fontSize: 12 }}> + moment(item).format('MM/DD HH:mm') + // </div> + ); + }, + }, + { + title: '早到时长', + dataIndex: 'earlyMinute', + key: 'earlyMinute', + render: (item, cur) => { + return item + '分钟'; + }, + }, + ], + }, }; diff --git a/src/components/common/Tree/index.jsx b/src/components/common/Tree/index.jsx new file mode 100644 index 0000000..e43e32b --- /dev/null +++ b/src/components/common/Tree/index.jsx @@ -0,0 +1,210 @@ +/* eslint-disable */ +import React from 'react'; +import { Row, Col, Tree, Input, Icon, Button } from 'antd'; + +const TreeNode = Tree.TreeNode; +const Search = Input.Search; + +const getParentKey = (title, tree) => { + let parentKey; + for (let i = 0; i < tree.length; i++) { + const node = tree[i]; + if (node.children) { + if (node.children.some(item => item.title === title)) { + parentKey = node.key; + } else if (getParentKey(title, node.children)) { + parentKey = getParentKey(title, node.children); + } + } + } + return parentKey; +}; + +export default class SearchTree extends React.Component { + constructor(props) { + super(props) + this.gData = this.props.data; + this.dataList = [] + this.state = { + expandedKeys: props.expandedKeys, + selectedKeys: props.selectedKeys, + clickEle: '', + searchValue: '', + autoExpandParent: true, + showSearch: true, + checkable: false + } + } + componentDidMount() { + const generateList = (data) => { + for (let i = 0; i < data.length; i++) { + const node = data[i]; + const key = node.key; + const title = node.title; + this.dataList.push({ key, title }); + if (node.children) { + generateList(node.children, title); + } + } + }; + generateList(this.props.data) + } + + onExpand = (expandedKeys) => { + //this.props.onExpand(expandedKeys) + this.setState({ + expandedKeys, + autoExpandParent: false, + }); + } + + onChange = (e) => { + const value = e.target.value; + const expandedKeys = this.dataList.map((item) => { + if (item.title.indexOf(value) > -1) { + return getParentKey(item.title, this.gData); + } + return null; + }).filter((item, i, self) => item && self.indexOf(item) === i); + this.setState({ + expandedKeys, + searchValue: value, + autoExpandParent: true, + }); + } + + treeSelect = (selectedKeys, e) => { + console.log(selectedKeys) + let _this = this; + _this.props.onSelect && _this.props.onSelect(selectedKeys); + if (selectedKeys.length == 0 && typeof this.props.clearKeys !== "undefined") { + this.props.clearKeys(); + this.setState({ clickEle: '' });//置空点击节点 + } + const getOwnNodes = (data) => { + for (let i = 0; i < data.length; i++) { + const node = data[i] + const key = node.key; + if (key == selectedKeys) { + this.setState({ clickEle: node }); + if (data[i].children) { //如果有子,则返回所有子节点 + this.props.treeSelect(node.children, [node]) + } else { //没有子节点,就返回当前节点 + this.props.treeSelect([node], [node]) + } + return null; + } else { + if (data[i].children) { + getOwnNodes(data[i].children) + } + } + } + }; + getOwnNodes(this.gData) + } + + onCheck = (checkedKeys, { checked: bool, checkedNodes, node, event }) => { + console.log('checkedKeys', checkedKeys, 'checkedNodes', checkedNodes) + let _this = this; + let selectleafNodeKeys = []; + + for (var i = 0; i < checkedNodes.length; i++) { + if (checkedNodes[i].props.children && checkedNodes[i].props.children.length > 0) { + } else { + selectleafNodeKeys.push(checkedNodes[i].key) + } + } + console.log('子节点选中的key', selectleafNodeKeys); + let treeCheckArr = []; //选中节点的信息 + const getOwnNodes = (data, checkedKey) => { + let _this = this; + for (let i = 0; i < data.length; i++) { + const node = data[i] + if (node.key == checkedKey) { + if (data[i].children) { //如果有子,也返回当前节点 + treeCheckArr.push(data[i]); + } else { //没有子节点,就返回当前节点 + treeCheckArr.push(data[i]); + } + return null; + } else { + if (data[i].children) { + getOwnNodes(data[i].children, checkedKey) + } + } + } + }; + for (var j = 0; j < selectleafNodeKeys.length; j++) { + getOwnNodes(_this.gData, selectleafNodeKeys[j]); + } + _this.props.currentTreeCheck(treeCheckArr); + _this.props.onCheck(checkedKeys, checkedNodes); + } + + add = () => { + this.props.add() + } + + delete = () => { + this.props.delete(this.state.clickEle) + } + render() { + const { searchValue, expandedKeys, autoExpandParent, selectedKeys } = this.state; + const showSearch = typeof this.props.showSearch === "undefined" ? this.state.showSearch : this.props.showSearch; + const checkable = typeof this.props.checkable === "undefined" ? this.state.checkable : this.props.checkable; + + const loop = data => data.map((item) => { + const disabled = item.disabled || false; + const index = item.title.indexOf(searchValue); + const beforeStr = item.title.substr(0, index); + const afterStr = item.title.substr(index + searchValue.length); + const title = index > -1 ? ( + <span> + {beforeStr} + <span style={{ color: '#f50' }}>{searchValue}</span> + {afterStr} + </span> + ) : <span>{item.title}</span>; + if (item.children) { + return ( + <TreeNode key={item.key} title={title} disabled={disabled}> + {loop(item.children)} + </TreeNode> + ); + } + return <TreeNode key={item.key} title={title} disabled={disabled} />; + }); + + return ( + + <div> + <div style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}> + {showSearch && <Search style={{ marginBottom: 1 }} placeholder="搜索资源名称" onChange={this.onChange} />} + {this.props.add && <Button onClick={this.add} style={{ marginLeft: 5 }}><Icon type="plus-circle-o" style={{ fontSize: 16 }} /></Button>} + {this.props.delete && <Button onClick={this.delete} style={{ marginLeft: 5 }}><Icon type="delete" style={{ fontSize: 16 }} /></Button>} + </div> + { + this.gData.length > 0 && + // style={{height: 413, overflowY: 'auto'}} + <div> + <Tree + defaultExpandAll={true} + onSelect={this.treeSelect} + // onExpand={this.onExpand} + // expandedKeys={expandedKeys} + autoExpandParent={autoExpandParent} + showLine + checkable={checkable} + onCheck={this.onCheck} + checkedKeys={this.props.checkedKeys} + selectedKeys={this.props.selectedKeys} + > + {loop(this.gData)} + </Tree> + </div> + } + </div> + ); + } +} + diff --git a/src/components/page/AnnouncementPage/index.jsx b/src/components/oa/AnnouncementPage/index.jsx similarity index 100% rename from src/components/page/AnnouncementPage/index.jsx rename to src/components/oa/AnnouncementPage/index.jsx diff --git a/src/components/page/AnnouncementPage/index.scss b/src/components/oa/AnnouncementPage/index.scss similarity index 100% rename from src/components/page/AnnouncementPage/index.scss rename to src/components/oa/AnnouncementPage/index.scss diff --git a/src/components/page/DocumentDetailPage/index.jsx b/src/components/oa/DocumentDetailPage/index.jsx similarity index 100% rename from src/components/page/DocumentDetailPage/index.jsx rename to src/components/oa/DocumentDetailPage/index.jsx diff --git a/src/components/page/DocumentDetailPage/index.scss b/src/components/oa/DocumentDetailPage/index.scss similarity index 100% rename from src/components/page/DocumentDetailPage/index.scss rename to src/components/oa/DocumentDetailPage/index.scss diff --git a/src/components/page/DocumentEditPage/index.jsx b/src/components/oa/DocumentEditPage/index.jsx similarity index 100% rename from src/components/page/DocumentEditPage/index.jsx rename to src/components/oa/DocumentEditPage/index.jsx diff --git a/src/components/page/DocumentEditPage/index.scss b/src/components/oa/DocumentEditPage/index.scss similarity index 100% rename from src/components/page/DocumentEditPage/index.scss rename to src/components/oa/DocumentEditPage/index.scss diff --git a/src/components/page/basicConfig/UserDetail.jsx b/src/components/oa/basicConfig/UserDetail.jsx similarity index 100% rename from src/components/page/basicConfig/UserDetail.jsx rename to src/components/oa/basicConfig/UserDetail.jsx diff --git a/src/components/page/basicConfig/UserManage.jsx b/src/components/oa/basicConfig/UserManage.jsx similarity index 97% rename from src/components/page/basicConfig/UserManage.jsx rename to src/components/oa/basicConfig/UserManage.jsx index 4e5a7c5..8f49e23 100644 --- a/src/components/page/basicConfig/UserManage.jsx +++ b/src/components/oa/basicConfig/UserManage.jsx @@ -101,7 +101,7 @@ return <div> <Link to={{ pathname: "/baseManage/userDetail/" + record.id + '/Modify', query: { id: record.id } }}>修改</Link> <Divider type="vertical" /> - <a href="javascript:void(0);" onClick={() => this.delete(record.id)}>删除</a> + <a onClick={() => this.delete(record.id)}>删除</a> </div> } } diff --git a/src/components/page/index/rulesList/index.jsx b/src/components/oa/index/rulesList/index.jsx similarity index 100% rename from src/components/page/index/rulesList/index.jsx rename to src/components/oa/index/rulesList/index.jsx diff --git a/src/components/page/index/rulesList/index.scss b/src/components/oa/index/rulesList/index.scss similarity index 100% rename from src/components/page/index/rulesList/index.scss rename to src/components/oa/index/rulesList/index.scss diff --git a/src/components/page/index/workbench/index.jsx b/src/components/oa/index/workbench/index.jsx similarity index 100% rename from src/components/page/index/workbench/index.jsx rename to src/components/oa/index/workbench/index.jsx diff --git a/src/components/page/index/workbench/index.scss b/src/components/oa/index/workbench/index.scss similarity index 100% rename from src/components/page/index/workbench/index.scss rename to src/components/oa/index/workbench/index.scss diff --git a/src/components/page/logManage/Rawler/index.jsx b/src/components/oa/logManage/Rawler/index.jsx similarity index 100% rename from src/components/page/logManage/Rawler/index.jsx rename to src/components/oa/logManage/Rawler/index.jsx diff --git a/src/components/page/logManage/Rawler/index.scss b/src/components/oa/logManage/Rawler/index.scss similarity index 100% rename from src/components/page/logManage/Rawler/index.scss rename to src/components/oa/logManage/Rawler/index.scss diff --git a/src/components/page/logManage/browseLog/index.jsx b/src/components/oa/logManage/browseLog/index.jsx similarity index 100% rename from src/components/page/logManage/browseLog/index.jsx rename to src/components/oa/logManage/browseLog/index.jsx diff --git a/src/components/page/logManage/browseLog/index.scss b/src/components/oa/logManage/browseLog/index.scss similarity index 100% rename from src/components/page/logManage/browseLog/index.scss rename to src/components/oa/logManage/browseLog/index.scss diff --git a/src/components/page/logManage/operLog/index.jsx b/src/components/oa/logManage/operLog/index.jsx similarity index 100% rename from src/components/page/logManage/operLog/index.jsx rename to src/components/oa/logManage/operLog/index.jsx diff --git a/src/components/page/logManage/operLog/index.scss b/src/components/oa/logManage/operLog/index.scss similarity index 100% rename from src/components/page/logManage/operLog/index.scss rename to src/components/oa/logManage/operLog/index.scss diff --git a/src/components/page/personal/information/index.jsx b/src/components/oa/personal/information/index.jsx similarity index 100% rename from src/components/page/personal/information/index.jsx rename to src/components/oa/personal/information/index.jsx diff --git a/src/components/page/personal/information/index.scss b/src/components/oa/personal/information/index.scss similarity index 100% rename from src/components/page/personal/information/index.scss rename to src/components/oa/personal/information/index.scss diff --git a/src/index.css b/src/index.css index 21dc559..07d27b8 100644 --- a/src/index.css +++ b/src/index.css @@ -34,6 +34,10 @@ padding: 9px 8px !important; } +.border{ + border: 20px solid #ededed; +} + .margin { margin: 20px; } @@ -54,4 +58,64 @@ margin-bottom: 20px; } +.fontSize12{ + font-size: 12px; +} + +.ant-divider-horizontal{ + margin: 20px 0 !important; +} + +.margin-bottom{ + margin-bottom: 20px; +} + +.ant-card-head-title{ + font-weight: bold !important; +} + +div{ + box-sizing: border-box; +} + +.flex-box-column{ + display: flex; + flex-direction: column; +} + +.flex-box { + display: flex; +} + +.align-center{ + align-items: center; +} + +.justify-content{ + justify-content: center; +} + +.flex-1 { + flex: 1; + overflow: auto; +} + +.ant-spin-nested-loading{ + height: 100%; +} +.ant-spin-container{ + height: 100%; +} + +.treeNodeUnselectable { + -webkit-user-select: none; + -moz-user-select: none; + -o-user-select: none; + -ms-user-select: none; +} + +.ant-alert.ant-alert-no-icon { + padding: 2px 8px !important; +} + diff --git a/src/index.js b/src/index.js index ffa772b..cb0f05c 100644 --- a/src/index.js +++ b/src/index.js @@ -3,9 +3,6 @@ import ReactDOM from 'react-dom'; import './index.css'; -import Menu from './pages/menu/menu'; -import Header from './components/common/HeadView'; - import * as serviceWorker from './serviceWorker'; import { Router, Route, Switch, Redirect } from 'react-router-dom'; import { ConfigProvider } from 'antd'; @@ -17,82 +14,111 @@ import 'react-app-polyfill/ie11'; import 'react-app-polyfill/stable'; -// 引进页面(pages) -import Index from './pages/Index'; -import Login from './pages/login/login'; -import Workbench from './pages/index/workbench'; //首页--工作台 -import System from './pages/index/System'; //首页--工作制度 -import Announcement from './pages/index/Announcement'; //全部通知 +// 公用结构组件 +import Menu from './module/menu/menu'; +import Header from './components/common/HeadView'; -import DocumentEdit from './pages/document/DocumentEdit'; //新建文档 -import DocumentDetail from './pages/document/DocumentDetail'; //文档详情 -import BrowseLog from './pages/logManage/browseLog'; //浏览日志 -import OperLog from './pages/logManage/operLog'; //操作日志 -import Rawler from './pages/logManage/Rawler'; //爬虫词条管理 -import Information from './pages/personal/information'; //个人信息 +// oa路由映射 +import OaRouteDom from './routeDom/oaRouteDom'; +import UserRouteDom from './routeDom/userRouteDom'; -// 基础平台 -import UserManage from './components/page/basicConfig/UserManage';//用户管理 +export const Context = React.createContext(); const { Content } = Layout; const history = createHashHistory(); -ReactDOM.render( - <ConfigProvider locale={zh_CN}> - <Router history={history}> - <Layout className="h-100"> - <Switch> - <Route path="/login" component={null} /> - <Route component={Menu} /> - </Switch> - <Layout> - <Switch> - <Route path="/login" component={null} /> - <Route component={Header} /> - </Switch> - <Content> - <Switch> - {/* 基础平台 */} - <Route path="/baseManage/user" component={UserManage} /> +class RouteDom extends React.Component { + constructor(props) { + super(props); + this.state = { + context: { + role: 'oa', + roleMenuList: [], + setContext: this.setContext, + }, + }; + } - {/* 新建文档 */} - <Route path="/document/create/:id?" component={DocumentEdit} /> - {/* 文档、通知详情 */} - <Route path="/document/detail/:id" component={DocumentDetail} /> + componentDidMount() { + let pathname = history.location.pathname; + let menusListByRole = window.localStorage.getItem('menusListByRole') + ? JSON.parse(window.localStorage.getItem('menusListByRole')) + : []; - {/* 全部通知 */} - <Route - path="/index/workbench/announcement" - component={Announcement} - /> - {/* 规章制度 */} - <Route path="/index/rules" component={System} /> - {/* 首页 */} - <Route path="/index" component={Workbench} /> + let role = Object.keys(menusListByRole).reduce((p, n) => { + if ( + menusListByRole[n].menus + .reduce((p, n) => { + if (n.children) { + return p.concat(n.children); + } else { + return p.concat(n); + } + }, []) + .find(({ path }) => path == pathname) + ) { + return p.concat(n); + } else { + return p; + } + }, []); - {/* 浏览日志 */} - <Route path="/logManage/browseLog" component={BrowseLog} /> - {/* 操作日志 */} - <Route path="/logManage/operLog" component={OperLog} /> - {/* 爬虫词条管理 */} - <Route path="/logManage/rawler" component={Rawler} /> - {/* 个人信息 */} - <Route path="/personal/information" component={Information} /> + this.setState({ + context: { + ...this.state.context, + role, + }, + }); + } - {/* 登录页 */} - <Route path="/login" component={Login} /> - <Route path="/" component={Workbench} /> + setContext = (data) => { + console.log('data', data); + this.setState({ + context: { + ...this.state.context, + ...data, + }, //更新context + }); + }; - {/* 路由的页面重定向 */} - <Redirect to="/" component={Workbench} /> - </Switch> - </Content> - </Layout> - </Layout> - </Router> - </ConfigProvider>, - document.getElementById('root') -); + render() { + let { context } = this.state; + return ( + <ConfigProvider locale={zh_CN}> + <Context.Provider value={context}> + <Router history={history}> + <Layout className="h-100"> + {/* 顶部-侧边布局-通栏 */} + {/* 顶部 */} + <Switch> + <Route path="/login" component={null} /> + <Route + component={() => ( + <Header setContext={this.setContext} props={this.props} /> + )} + /> + </Switch> + <Layout> + <Switch> + <Route path="/login" component={null} /> + <Route component={Menu} /> + </Switch> + <Layout> + <Content> + {context.role == 'oa' && <OaRouteDom />} + {context.role == 'user' && <UserRouteDom />} + </Content> + </Layout> + </Layout> + </Layout> + </Router> + </Context.Provider> + </ConfigProvider> + ); + } +} + +ReactDOM.render(<RouteDom></RouteDom>, document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. diff --git a/src/menu/index.js b/src/menu/index.js index 124e39c..452d5ae 100644 --- a/src/menu/index.js +++ b/src/menu/index.js @@ -1,2 +1,3 @@ -export { default as menus } from './menu.data'; +export { default as oaMenus } from './menu.oa'; +export { default as userMenus } from './menu.user'; export { default as getMenuListByPermission } from './menu.permission'; \ No newline at end of file diff --git a/src/menu/menu.data.js b/src/menu/menu.oa.js similarity index 69% rename from src/menu/menu.data.js rename to src/menu/menu.oa.js index ea7a8d4..6838ce9 100644 --- a/src/menu/menu.data.js +++ b/src/menu/menu.oa.js @@ -107,32 +107,32 @@ }, { key: '/logManage/rawler', - name: "爬虫词条管理", - path: "/logManage/rawler", + name: '爬虫词条管理', + path: '/logManage/rawler', permKey: '/logManage/rawler', parentKey: '/logManage', children: [], }, ], }, - { - key: 'administration', - name: '用户管理', - path: 'administration', - icon: 'team', - permKey: 'administration', - children: [ - { - key: '/administration', - name: '用户中心', - path: 'http://120.79.193.119:9074/base/login.html#/', - permKey: 'http://120.79.193.119:9074/base/login.html#/', - children: [], - parentKey: 'administration', - type: 'open', - }, - ], - }, + // { + // key: 'administration', + // name: '用户管理', + // path: 'administration', + // icon: 'team', + // permKey: 'administration', + // children: [ + // { + // key: '/administration', + // name: '用户中心', + // path: 'http://120.79.193.119:9074/base/login.html#/', + // permKey: 'http://120.79.193.119:9074/base/login.html#/', + // children: [], + // parentKey: 'administration', + // type: 'open', + // }, + // ], + // }, { key: 'personal', name: '个人中心', @@ -150,6 +150,39 @@ }, ], }, + { + key: 'merits', + name: '绩效管理', + path: 'merits', + icon: 'user', + permKey: 'merits', + children: [ + { + key: '/merits/meritsOverview', + name: '绩效总览', + path: '/merits/meritsOverview', + permKey: '/merits/meritsOverview', + children: [], + parentKey: 'merits', + }, + { + key: '/merits/meritsExamine', + name: '绩效考核', + path: '/merits/meritsExamine', + permKey: '/merits/meritsExamine', + children: [], + parentKey: 'merits', + }, + { + key: '/merits/meritsDispose', + name: '参数配置', + path: '/merits/meritsDispose', + permKey: '/merits/meritsDispose', + children: [], + parentKey: 'merits', + }, + ], + }, ]; export default menus; diff --git a/src/menu/menu.user.js b/src/menu/menu.user.js new file mode 100644 index 0000000..99927b1 --- /dev/null +++ b/src/menu/menu.user.js @@ -0,0 +1,88 @@ +/** + * 菜单列表 + * key, path需要保持唯一 + * permKey表示权限Key值 + */ +const menus = [ + { + name: '用户管理', + path: '/baseManage/user', + icon: 'user', + }, + { + name: '组管理', + path: '/baseManage/group', + icon: 'team', + }, + { + name: '组织管理', + icon: 'solution', + path: '/organizationMgt', + children: [ + { + name: '单位管理', + path: '/organizationMgt/unit', + parentKey: '/organizationMgt', + }, + { + name: '部门管理', + path: '/organizationMgt/department', + parentKey: '/organizationMgt', + }, + { + name: '岗位管理', + path: '/organizationMgt/job', + parentKey: '/organizationMgt', + }, + ], + }, + { + name: '资源管理', + icon: 'book', + path: '/resourceMgt', + children: [ + { + name: '应用服务管理', + path: '/resourceMgt/appService', + parentKey: '/resourceMgt' + }, + { + name: '模块管理', + path: '/resourceMgt/modules', + parentKey: '/resourceMgt' + }, + { + name: '功能管理', + path: '/resourceMgt/function', + parentKey: '/resourceMgt' + }, + ], + }, + { + name: '权限管理', + icon: 'tool', + path: '/authorityMgt', + children: [ + { + name: '角色管理', + path: '/authorityMgt/role', + parentKey: '/authorityMgt' + }, + { + name: '权限管理', + path: '/authorityMgt/authority', + parentKey: '/authorityMgt' + }, + ], + }, + // ,{ + // name: '工作流管理', + // children: [{ + // name: '流程部署管理', + // path: '/activitiManage/deploy', + // } + // ] + // } +]; + +export default menus; diff --git a/src/module/huge-base/ActivitiDetail.jsx b/src/module/huge-base/ActivitiDetail.jsx new file mode 100644 index 0000000..88f63bd --- /dev/null +++ b/src/module/huge-base/ActivitiDetail.jsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Icon, Button, Table, message,Breadcrumb,Layout } from 'antd'; +import Fetch from '../fetch'; +const { Column } = Table; + + +export default class ActivitiDetail extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: true, + tableData: [], + }; + } + + componentDidMount() { + const deploymentId = this.props.location.state.deploymentId; + let _this = this; + _this.setState({ loading: true }); + Fetch.getProcessDefinition({ + deploymentId + }).then( res => { + console.log(res) + let tmpArr = []; + res.map(e => { + let obj = { + key: e.id, + _key:e.key, + id:e.id, + version:e.version, + status:e.status, + name: e.name, + createTime: e.createTime, + } + tmpArr.push(obj) + }) + this.setState({ + tableData: tmpArr, + loading: false, + }); + }) + } + + render() { + return ( + <Layout className="h-100 page-table"> + <Row> + <Breadcrumb className="breadcrumb-style"> + <Breadcrumb.Item>工作流管理</Breadcrumb.Item> + <Breadcrumb.Item>流程部署管理</Breadcrumb.Item> + <Breadcrumb.Item>详情</Breadcrumb.Item> + </Breadcrumb> + </Row> + <Card style={{border:20, margin:20, padding:20}}> + <Row> + <Link to="/activitiManage/deploy"><Button type="default">返回</Button></Link> + </Row> + <Row> + <Table dataSource={this.state.tableData} pagination={false}> + <Column + title="流程KEY" + dataIndex="_key" + key="_key" + /> + <Column + title="流程名称" + dataIndex="name" + key="name" + /> + <Column + title="流程版本" + dataIndex="version" + key="version" + /> + <Column + title="当前状态" + dataIndex="status" + key="status" + render={(text, record) => text?"运行":"挂起"} + /> + <Column + title="操作" + key="action" + render={(text, record) => ( + <span> + <Link to={{ pathname: "/activitiManage/activitiImg", state: { id: record.id} }}>流程图</Link> + </span> + )} + /> + </Table> + + </Row> + </Card> + </Layout> + ) + } +} diff --git a/src/module/huge-base/ActivitiImg.jsx b/src/module/huge-base/ActivitiImg.jsx new file mode 100644 index 0000000..e5342cc --- /dev/null +++ b/src/module/huge-base/ActivitiImg.jsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Icon, Button,message,Breadcrumb,Layout } from 'antd'; +import { domain } from '../fetch/_'; + +export default class ActivitiImg extends React.Component { + + render() { + return ( + <Layout className="h-100 page-table"> + <Row> + <Breadcrumb className="breadcrumb-style"> + <Breadcrumb.Item>工作流管理</Breadcrumb.Item> + <Breadcrumb.Item>流程部署管理</Breadcrumb.Item> + <Breadcrumb.Item>流程图</Breadcrumb.Item> + </Breadcrumb> + </Row> + <Card style={{border:20, margin:20, padding:20}}> + <Row> + <Row style={{borderStyle:'solid', borderWidth:0.01}}> + <span style={{fontSize:25}}>流程图</span> + <div style={{float:'right'}}> + <Link to="/activitiManage/deploy"><Button type="default">返回</Button></Link> + </div> + </Row> + </Row> + <img src={ domain+"api/workflow/image?processDefinitionId=" + this.props.location.state.id } + style={{ border: "1px solid #999" }}/> + </Card> + </Layout> + ) + } +} diff --git a/src/module/huge-base/AppServiceDetail.jsx b/src/module/huge-base/AppServiceDetail.jsx new file mode 100644 index 0000000..79e9898 --- /dev/null +++ b/src/module/huge-base/AppServiceDetail.jsx @@ -0,0 +1,143 @@ +import React from 'react'; +import { Card, Row, Col, Form, Input, Button, message, Spin } from 'antd'; +import { createHashHistory } from 'history'; +import fetch from '../../api/request'; + +const history = createHashHistory(); +const FormItem = Form.Item; +const { TextArea } = Input; + +class AppServiceDeatil extends React.Component { + constructor(props) { + super(props) + this.id = props.match.params.id == 'new' ? '' : props.match.params.id; + this.flag = props.match.params.flag == 'Modify' ? '修改' : '新增'; + + this.state = { + spinning: false,//页面loading + dataSet: {} + } + } + + componentWillMount() { } + + //获取应用服务详情 + componentDidMount() { + if (this.id !== '') { + this.setState({ spinning: true }); + fetch({ + url: `api/app/getById`, + params: { id: this.id } + }).then(res => { + this.setState({ loading: false }); + if (res) { + this.setState({ dataSet: res, spinning: false }); + } + }) + } + } + + // 提交表单数据(保存) + handleSubmit = (e) => { + e.preventDefault(); + this.props.form.validateFields((err, values) => { + if (err) return; + this.setState({ spinning: true }); + fetch({ + url: `api/app/save`, + method: 'POST', + data: { ...values, id: this.id } + }).then(res => { + this.setState({ spinning: false }); + if (res) { + message.success('保存成功'); + history.goBack();//返回至列表页面 + } + }) + }) + } + + //返回上一个页面 + onBack = () => { + history.goBack(); + } + + render() { + const { getFieldDecorator } = this.props.form; + const { dataSet } = this.state; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + + return ( + <div className="appservicedetail-main h-100 margin padding bg-white"> + <Spin spinning={this.state.spinning}> + <div> + <Form onSubmit={this.handleSubmit}> + <Card title={this.id ? '应用服务信息编辑' : '应用服务信息新增'} bordered={false} + extra={<Row type="flex" gutter={20}> + <Col> + <Button onClick={this.onBack}>返回</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit">确定</Button> + </Col> + </Row>} + > + <Row type="flex"> + <Col span={14}> + <FormItem label={"名称"} {...formItemLayout}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '请输入名称' }], + initialValue: dataSet.name || '' + })( + <Input placeholder="请输入描述" rows={5} /> + )} + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={14}> + <FormItem label={"根路径"} {...formItemLayout}> + {getFieldDecorator('rootUrl', { + rules: [{ required: true, message: '请输入根路径' }], + initialValue: dataSet.rootUrl || '', + })( + <Input placeholder="请输入根路径" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={14}> + <FormItem label={"标识符"} {...formItemLayout}> + {getFieldDecorator('symbol', { + rules: [{ required: true, message: '请输入标识符' }], + initialValue: dataSet.symbol || '', + })( + <Input placeholder="请输入标识符" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={14}> + <FormItem label={"描述"} {...formItemLayout}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description || '' + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + ) + } +} + +const AppServiceDeatilForm = Form.create()(AppServiceDeatil); +export default AppServiceDeatilForm; \ No newline at end of file diff --git a/src/module/huge-base/AppServiceManage.jsx b/src/module/huge-base/AppServiceManage.jsx new file mode 100644 index 0000000..450ebf1 --- /dev/null +++ b/src/module/huge-base/AppServiceManage.jsx @@ -0,0 +1,113 @@ +/* eslint-disable */ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Icon, Form, Input, Button, Select, Table, DatePicker, message, Breadcrumb, Layout, Popconfirm, Divider, Modal } from 'antd'; +import TableView from '../../components/common/TableView'; +import SearchFormView from '../../components/common/SearchFormView'; +import moment from 'moment'; +import fetch from '../../api/request'; + +const FormItem = Form.Item; +const confirm = Modal.confirm; + + +export default class AppServiceManage extends React.Component { + constructor(props) { + super(props); + this.state = { + formData: { + __key: Date.now(), + page: 1, + size: 10, + }, + }; + } + + componentDidMount() { } + + setFormData = data => { + this.setState({ + formData: data, + }); + } + + //添加应用 + add = () => { + this.props.history.push('/resourceMgt/appService/Detail/new/Add') + } + + //删除应用 + delete = (id) => { + let _this = this; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该应用吗?</span>, + onOk() { + fetch({ + url: `api/function/delete`, + params: { ids: id } + }).then(res => { + if (res) { + message.success("删除成功"); + _this.setState({ + formData: { + ..._this.state.formData, + __key: Date.now() + } + }) + } + }) + }, + onCancel() { }, + }); + } + + //表格列显示 + renderColumns = () => { + return [ + { title: '名称', className: "txt-c", dataIndex: 'name', key: 'name' }, + { title: '根路径', className: "txt-c", dataIndex: 'rootUrl', key: 'rootUrl' }, + { title: '标识符', className: "txt-c", dataIndex: 'symbol', key: '' }, + { title: '创建时间', className: "txt-c", dataIndex: 'updateTime', key: 'updateTime', render: (text, record) => text !== "" && text != null ? moment(text).format("YYYY-MM-DD HH:mm") : "" }, + { + title: '操作', className: "txt-c", key: 'operation', render: (text, record) => { + return <div> + <Link to={{ pathname: "/resourceMgt/appService/Detail/" + record.id + '/Modify', state: { id: record.id } }}>修改</Link> + <span> | </span> + <a onClick={() => this.delete(record.id)}>删除</a> + </div> + } + } + ] + } + render() { + const { formData, userSyncLoading } = this.state; + let tableParams = { + url: `api/app/query`, + formData, + key: formData.__key, + columns: this.renderColumns(), + extraFromData: {}, + setFormData: this.setFormData + } + + return ( + <div className="appservicemanage-main h-100 margin padding bg-white"> + <SearchFormView + formData={formData} + setFormData={this.setFormData} + data={[ + { type: 'input', name: '名称', label: '名称', key: 'name' }, + { type: 'input', name: '标识符', label: '标识符', key: 'symbol' }, + ]} /> + <Row type="flex" className="margin-bottom"> + <Col> + <Button type="primary" onClick={this.add}>新增</Button> + </Col> + </Row> + <TableView {...tableParams} /> + </div> + ) + } + + +} diff --git a/src/module/huge-base/AuthorityManage.jsx b/src/module/huge-base/AuthorityManage.jsx new file mode 100644 index 0000000..d42204d --- /dev/null +++ b/src/module/huge-base/AuthorityManage.jsx @@ -0,0 +1,267 @@ +import React from 'react'; +import { Card, Row, Col, Icon, Form, Input, Button, Table, DatePicker, message, Breadcrumb, Tree, Modal, Layout, Popconfirm, List, Spin, Empty } from 'antd'; +import SearchTree from '../../components/common/Tree'; +import fetch from '../../api/request'; + +const Search = Input.Search; +const confirm = Modal.confirm; + +class ResourceManage extends React.Component { + constructor(props) { + super(props); + this.state = { + spinning: false, + resourceList: [], + treeKey: 'init', + expandedKeys: [], + treeData: [], + edit: 'false', + rightShow: false, + dataSet: {}, + currentNode: [], + + roleList: [], //角色列表 + resourceIds: [], //资源集合 + treeCheckArr: [], + roleId: '', + checkedKeys: [], + + leftRoleLoading: false,//左侧角色列表loading + rightTreeRightLoading: false,//右侧角色对应菜单权限loading + + }; + } + + componentDidMount() { + this.findRoles(); + this.getAllFunctionsByTree(); + } + + //取消按钮 + cancelFun = () => { + this.setState({ + edit: 'false', + rightShow: false, + roleId: '' + }) + } + + //所有角色列表 + findRoles = () => { + this.setState({ leftRoleLoading: true }); + fetch({ + url: `api/role/finds` + }).then(res => { + this.setState({ leftRoleLoading: false }); + if (res) { + this.setState({ roleList: res }); + } + }) + } + + //加载所有应用菜单树形结构 + getAllFunctionsByTree = () => { + this.setState({ rightTreeRightLoading: true }); + fetch({ + url: `api/function/getAllFunctionsByTree`, + }).then(res => { + this.setState({ rightTreeRightLoading: false }); + if (res) { + for (let i = 0; i < res.length; i++) { + res[i].resourceType = 1; + } + res = this.handleTreeData(res); + this.setState({ treeData: res }) + } + }) + } + + //通过角色id查询对应角色的菜单权限 + getResourcesByRoleId = (id) => { + this.setState({ rightTreeRightLoading: true }); + fetch({ + url: `api/role/getResourcesByRoleId`, + params: { roleId: id } + }).then(res => { + this.setState({ rightTreeRightLoading: false }); + console.log('res', res); + if (res) { + this.setState({ + checkedKeys: res.map(({ id }) => id), + treeCheckArr: res + }) + } + }) + } + + //处理树形数据结构 + handleTreeData = data => { + for (let i = 0; i < data.length; i++) { + const node = data[i]; + node.key = node.id; + node.title = node.name; + if (data[i].modules) { + data[i].children = data[i].modules; + this.handleTreeData(node.children); + } + if (data[i].children) { + this.handleTreeData(node.children); + } + if (data[i].functions) { + data[i].children = data[i].functions; + this.handleTreeData(node.children); + } + } + return data; + }; + + + treeSelect = (tableData, currentNode) => { + console.log(tableData, currentNode); + // 点击任意节点都可以查看、编辑、添加 + this.setState({ + rightShow: true + }) + this.setState({ + leafNodes: tableData, + currentNode + }) + }; + + currentTreeCheck = (treeCheckArr) => { + this.setState({ + treeCheckArr + }) + } + + onExpand = (expandedKeys) => { + this.setState({ + expandedKeys, + }); + } + + //选中角色 + selectRole = (e) => { + let roleId = e.target.getAttribute("data-roleid"); + console.log(roleId) + this.setState({ + rightShow: true, + roleId, + spinning: true + }, () => { + this.getResourcesByRoleId(this.state.roleId);//查询角色权限 + }) + } + + onCheck = (checkedKeys, checkedNodes) => { + console.log('checkedNodes', checkedNodes); + this.setState({ + checkedKeys + }) + } + + saveFun = () => { + const { treeCheckArr, roleId, funs } = this.state; + let resourceIds = []; + + console.log(resourceIds, treeCheckArr); + this.setState({ rightTreeRightLoading: true }); + fetch({ + url: `api/role/auth`, + method: 'POST', + data: { + roleId, + resourceIds: treeCheckArr.map(({ id, resourceType }) => ({ resourceId: id, resourceType })) + } + }).then(res => { + this.setState({ rightTreeRightLoading: false }); + if (res) { + message.success('配置保存成功'); + } + }) + } + + render() { + const { rightShow, treeData, roleList, roleId, leftRoleLoading, rightTreeRightLoading } = this.state; + + return ( + <div className="authormanage-main h-100 margin padding bg-white"> + + <div className="padding h-100" > + <Row style={{ height: '100%' }} > + <Col span={8} style={{ border: "1px solid #e8e8e8", padding: 10 }} className="h-100"> + <Spin spinning={leftRoleLoading}> + <Row style={{ marginTop: 10 }} > + + { + roleList.map((item, idx) => { + return ( + roleId == item.id ? + <div key={item.id} data-roleid={item.id} onClick={this.selectRole} style={{ border: "1px solid #e8e8e8", padding: 8, textAlign: 'center', cursor: 'pointer' }} className="ant-btn-primary ant-menu-submenu-selected"> + {item.name} + </div> : + <div key={item.id} data-roleid={item.id} onClick={this.selectRole} style={{ border: "1px solid #e8e8e8", padding: 8, textAlign: 'center', cursor: 'pointer' }}> + {item.name} + </div> + ) + }) + } + </Row> + </Spin> + </Col> + <Col span={1}></Col> + <Col span={15} style={{ border: "1px solid #e8e8e8" }} className="h-100"> + {rightShow && + <div className="h-100"> + <Spin spinning={rightTreeRightLoading} height={'100%'}> + <div> + <Form> + <Card title={'模块权限配置'} bordered={false} extra={ + <Row type="flex" gutter={20}> + <Col> + <Button onClick={this.cancelFun}>取消</Button> + </Col> + <Col> + <Button className="button-do" htmlType="submit" onClick={this.saveFun} type="primary">保存</Button> + </Col> + </Row> + }> + {/* 此处的key用于控制滚动条的位置 */} + <div style={{ height: '65vh', overflow: 'auto' }} key={roleId}> + <SearchTree + data={treeData} + onExpand={this.onExpand} + expandedKeys={this.state.expandedKeys} + treeSelect={this.treeSelect} + showSearch={false} + checkable={true} + defaultExpandAll={true} + currentTreeCheck={this.currentTreeCheck} + checkedKeys={this.state.checkedKeys} + onCheck={this.onCheck} + /> + </div> + </Card> + </Form> + </div> + </Spin> + </div> + } + { + !rightShow && + <Empty description={'暂无数据,请点击左侧树形结构'} className="h-100 flex-box-column align-center justify-content" /> + } + </Col> + </Row> + <Row> + </Row> + </div> + </div> + ) + } +} + + + +const ResourceManageList = Form.create()(ResourceManage); +export default ResourceManageList; \ No newline at end of file diff --git a/src/module/huge-base/DepartmentManage.jsx b/src/module/huge-base/DepartmentManage.jsx new file mode 100644 index 0000000..9a37d84 --- /dev/null +++ b/src/module/huge-base/DepartmentManage.jsx @@ -0,0 +1,316 @@ +/* eslint-disable */ +import React from "react"; +import { Row, Col, Form, Button, message, Modal, Popconfirm, Empty, Spin } from "antd"; +import moment from "moment"; +import SearchTree from '../../components/common/Tree'; +import SearchFormView from '../../components/common/SearchFormView'; +import TableView from '../../components/common/TableView'; +import fetch from '../../api/request'; +import DeptDetail from './DeptDetail';//部门详情 + +const FormItem = Form.Item; +const confirm = Modal.confirm; + +export default class DepartmentManage extends React.Component { + constructor(props) { + super(props); + this.state = { + treeKey: "init", + expandedKeys: [], + tableData: [], + totalElements: 1, + pageSize: 10, + page: 1, + + treeData: [], + leafNodes: [], + currentNode: [], + rightShow: false, + modify: false, + parentId: '', + id: '', + dataSet: {}, + selectedKeys: [], + treeLoading: false,//左侧树结构loading + loading: false,//部门详情的loading + formData: { + __key: Date.now(), + page: 1, + size: 10, + } + + }; + } + componentDidMount() { + this.loadData(); + } + + //加载左侧树形数据 + loadData = () => { + this.setState({ + treeLoading: true + }) + fetch({ + url: `api/unit/getAllUnitsByCascade` + }).then(res => { + this.setState({ treeLoading: false }) + res = this.handleTreeData(res); + if (res) { + this.setState({ + treeData: res,//树形数据 + treeKey: Date.now() + }) + } + }) + }; + + //处理树形数据 + handleTreeData = data => { + for (let i = 0; i < data.length; i++) { + const node = data[i]; + node.key = node.id; + node.title = node.name; + if (data[i].children) { + this.handleTreeData(node.children); + } + } + return data; + }; + + //点击树形结构节点 + treeSelect = (tableData, currentNode) => { + // if (currentNode[0].children && currentNode[0].children.length > 0) { + // _this.setState({ + // rightShow: false + // }) + // message.error("请选择下级的节点"); + // return; + // } else { + // message.success("已选择" + currentNode[0].name) + // } + message.success("已选择:" + currentNode[0].name) + this.setState({ + leafNodes: tableData, + currentNode, + unitLocation: currentNode[0].name, + parentId: currentNode[0].parentId, + selectedKeys: [currentNode[0].id] + }, () => { + this.loadTableData() + }) + }; + + //加载右侧table表格数据 + loadTableData = () => { + let { formData, currentNode } = this.state; + this.setState({ + rightShow: true, + formData: { + ...formData, + __key: Date.now(), + unitId: currentNode[0].id + } + }) + } + + //点击table修改|新增按钮 + modifyFun = (id) => { + this.setState({ + modify: true, + id, + dataSet: {} + }) + if (id !== '') { + this.setState({ loading: true }); + fetch({ + url: `api/dept/getById`, + params: { id } + }).then(res => { + this.setState({ loading: false }); + if (res) { + this.setState({ dataSet: res }) + } + }) + } + } + + // 部门 新增|编辑 函数 + saveFun = (obj) => { + let { formData } = this.state; + this.setState({ loading: true }); + fetch({ + url: `api/dept/save`, + method: 'POST', + data: obj + }).then(res => { + this.setState({ loading: false }); + if (res) { + message.success('保存部门成功'); + this.setState({ + modify: false, + formData: { + ...formData, + __key: Date.now() + } + }); + } + }) + } + + //删除单位 + delete = (id) => { + let _this = this; + let { formData } = _this.state; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该部门吗?</span>, + onOk() { + fetch({ + url: `api/dept/delete`, + params: { ids: id } + }).then(res => { + if (res) { + message.success("删除成功"); + _this.setState({ + formData: { + ...formData, + __key: Date.now() + } + }); + } + }) + }, + onCancel() { }, + }); + } + + clearKeys = () => { + this.setState({ + currentNode: [], + rightShow: false, + }) + } + + cancelFun = () => { + this.setState({ + modify: false + }) + } + + onExpand = expandedKeys => { + this.setState({ + expandedKeys + }); + this.setState({ + treeKey: Date.now() + }); + }; + + onSelect = (selectedKeys) => { + this.setState({ + selectedKeys + }) + } + + setFormData = data => { + this.setState({ + formData: data, + }); + } + + renderColumns = () => { + return [ + { title: "部门名称", dataIndex: "name" }, + { title: "描述", dataIndex: "description", ellipsis: true }, + { title: '创建时间', dataIndex: 'updateTime', key: 'updateTime', render: (text, record) => text !== "" && text != null ? moment(text).format("YYYY-MM-DD HH:mm") : "" }, + { + title: "操作", + key: "operation", + render: (text, record) => { + return ( + <div> + <a onClick={() => this.modifyFun(record.id)}>修改</a> + <span> | </span> + <a onClick={() => this.delete(record.id)}>删除</a> + </div> + ); + } + } + ]; + }; + + render() { + const { treeKey, treeData, rightShow, treeLoading, formData, currentNode } = this.state; + + const params = { + id: this.state.id, + currentNode + } + + let tableParams = { + url: `api/dept/query`, + formData, + key: formData.__key, + columns: this.renderColumns(), + extraFromData: { + unitId: currentNode.length ? currentNode[0].id : '' + }, + setFormData: this.setFormData + } + + return ( + <div className="departmentmanage-main margin padding bg-white h-100"> + { + !this.state.modify && + <React.Fragment> + <div className="h-100 padding"> + <Row style={{ height: "100%" }}> + <Col span={8} style={{ border: "1px solid #e8e8e8", padding: 10 }} className="h-100"> + <Spin spinning={treeLoading}> + <SearchTree + key={treeKey} + data={treeData} + onExpand={this.onExpand} + expandedKeys={this.state.expandedKeys} + treeSelect={this.treeSelect} + clearKeys={this.clearKeys} + selectedKeys={this.state.selectedKeys} + onSelect={this.onSelect} + /> + </Spin> + </Col> + <Col span={1} /> + <Col span={15} style={{ border: "1px solid #e8e8e8", padding: 10 }} className="h-100"> + {rightShow && + <div> + <SearchFormView data={[{ type: 'input', name: '部门名称', label: '部门名称', key: 'name' }]} width={'50%'} formData={formData} setFormData={this.setFormData} /> + <Row className="margin-bottom"> + <Col> + <Button onClick={() => this.modifyFun('')} type="primary" className="button-do"> + 新增 + </Button> + </Col> + </Row> + <TableView {...tableParams} /> + </div> + } + { + !rightShow && + <Empty description={'暂无数据,请点击左侧树形结构'} className="h-100 flex-box-column align-center justify-content" /> + } + </Col> + + </Row> + </div> + </React.Fragment> + } + + {this.state.modify && + <DeptDetail cancelFun={this.cancelFun} params={params} dataSet={this.state.dataSet} saveFun={this.saveFun} loading={this.state.loading}></DeptDetail> + } + </div> + ); + } + +} + + diff --git a/src/module/huge-base/DeployManage.jsx b/src/module/huge-base/DeployManage.jsx new file mode 100644 index 0000000..20d8a55 --- /dev/null +++ b/src/module/huge-base/DeployManage.jsx @@ -0,0 +1,245 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Icon, Form, Input, Button, Select, Table, DatePicker, message,Breadcrumb,Upload,Modal, Layout } from 'antd'; +import moment from 'moment'; +import Fetch from '../fetch'; +import UploadXML from '../component/upload/index'; +import { deploymentDel } from '../fetch/api'; + +const FormItem = Form.Item; +const confirm = Modal.confirm; + +class DeployManage extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: true, + name:'', + tableData: [], + totalElements: 1, + pageSize:10, + page: 1 + }; + } + componentDidMount() { + this.loadData(1, this.state.pageSize); + } + render() { + const { name } = this.state; + const { getFieldDecorator } = this.props.form; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 10 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 14 }, }, + }; + const formItemLayout1 = { + labelCol: { xs: { span: 24 }, sm: { span: 8 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 16 }, }, + }; + const formMultiItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + return ( + <Layout className="h-100 page-table"> + <Row> + <Breadcrumb className="breadcrumb-style"> + <Breadcrumb.Item>工作流管理</Breadcrumb.Item> + <Breadcrumb.Item>流程部署管理</Breadcrumb.Item> + </Breadcrumb> + </Row> + <Card style={{border:20, margin:20, padding:20}}> + <Form onSubmit={this.handleSubmit} className="searchForm" layout="inline"> + <Row> + <Col span={7}> + <FormItem label="流程名称" {...formItemLayout1}> + {getFieldDecorator('name', { + rules: [{ required: false, whitespace: false }], + initialValue: '' + })( + <Input placeholder="请输入流程名称" /> + )} + </FormItem> + </Col> + <Col span={7}> + <FormItem {...formItemLayout1}> + <span style={{float:'right'}}> + <Button className="search-btn" htmlType="submit" type="primary"><Icon type='search' />查询</Button> + <Button className="search-btn" onClick={this.reset} >重置</Button> + </span> + </FormItem> + </Col> + </Row> + </Form> + <Row> + </Row> + <Row> + <Col span={7}> + <FormItem> + <UploadXML action={ "api/workflow/deploy"} ifSuccess={this.ifSuccess}/> + </FormItem> + </Col> + </Row> + <Row> + <Table + className="rowColor" + size="middle" + dataSource={this.state.tableData} + loading={{spinning: this.state.loading}} + columns={this.getColumns()} + pagination={{ + pageSize: this.state.pageSize, + onChange: this.pageChange, + total: this.state.totalElements, + showSizeChanger:true, + onShowSizeChange:this.onShowSizeChange, + showTotal:(total, range) => `共${total}条记录 `, + itemRender: this.itemRender, + showQuickJumper: true, + defaultCurrent: 1, + current: this.state.page + }} + /> + </Row> + </Card> + </Layout> + ) + } + + itemRender = (current, type, originalElement) => { + if (type === 'prev') { + return <a>上一页 </a>; + } else if (type === 'next') { + return <a> 下一页</a>; + } + return originalElement; + } + ifSuccess = result => { + result&&this.loadData(1,this.state.pageSize) + } + getColumns = () => { + let obj = this; + return [ + { title: '流程KEY', className: "txt-c", dataIndex: '_key'}, + { title: '流程名称', className: "txt-c", dataIndex: 'name' }, + { title: '当前状态', className: "txt-c", dataIndex: 'status', render:(text,record) =>text?"运行":"挂起" }, + { title: '流程版本', className: "txt-c", dataIndex: 'version' }, + { title: '创建时间', className: "txt-c", dataIndex: 'createTime', key: 'createTime', render: (text, record) => text !== "" && text != null ? moment(text).format("YYYY-MM-DD HH:mm") : "" }, + { title: '操作', className: "txt-c", key: 'operation', render: (text, record) => { + return <div> + <a onClick={()=>this.delete(record.deploymentId)}>删除</a> + <span> | </span> + <Link to={{ pathname: "/activitiManage/activitiImg", state: { id: record.id} }}>流程图</Link> + <span> | </span> + <Link to={{ pathname: "/activitiManage/activitiDetail", state: { deploymentId: record.id} }}>其他版本</Link> + </div> + } + } + ] + } + + delete = deploymentId => { + let _this= this + confirm({ + title: <span style={{fontSize:19}}>警告</span>, + content: <span style={{fontSize:18}}>确定删除吗</span>, + onOk() { + deploymentDel(deploymentId).then( res => { + if(res.code == 0) { + message.success("删除成功"); + _this.loadData(1,_this.state.pageSize) + }else{ + message.error(res.msg); + } + }) + }, + onCancel() {}, + }); + } + reset = () =>{ + this.props.form.setFieldsValue({ + name:'', + }); + this.loadData(1, this.state.pageSize) + } + handleSubmit = (e) => { + e.preventDefault(); + this.loadData(1, this.state.pageSize); + } + onShowSizeChange = (current, pageSize) =>{ + this.setState({pageSize, page: 1}) + this.loadData(1, pageSize); + } + pageChange = (page, pageSize) => { + this.loadData(page, pageSize); + } + loadData = (page, pageSize) => { + let _this = this; + _this.props.form.validateFields((err, values) => { + if (err) return; + _this.setState({ loading: true }); + let obj = { + key:values.key, + page: page, + pageSize: pageSize, + }; + // let promise = Get("/workflow/definition/listProcessDefinitionByPage?number=" + obj.page + "&size=" + obj.pageSize + "&key=" + obj.key); + // promise.then(reson => { + // let tmpArr = []; + // reson.data.content.map(e => { + // let obj = { + // key: e.id, + // _key:e.key, + // id:e.id, + // version:e.version, + // status:e.status, + // name: e.name, + // deploymentId:e.deploymentId, + // } + // tmpArr.push(obj) + // }) + + // this.setState({ + // tableData: tmpArr, + // totalElements: reson.data.totalElements, + // loading: false, + // }); + // }).catch(err => { + // this.setState({ loading: false }); + // message.error("数据加载失败,请稍后再试"); + // console.log(err.toString()); + // }); + + Fetch.getProcessDefinition({ + ...values, + page: page, + size: pageSize + }) + .then(res => { + let tmpArr = []; + res.map(e => { + let obj = { + key: e.id, + _key:e.key, + id:e.id, + version:e.version, + status:e.status, + name: e.name, + deploymentId:e.deploymentId, + createTime: e.createTime + } + tmpArr.push(obj) + }) + this.setState({ + tableData: tmpArr, + loading: false, + page, + totalElements: res.totalElements, + }); + }); + + }); + } +} +const header={"content-type":"multipart/form-data"} +const DeployManageList = Form.create()(DeployManage); +export default DeployManageList; \ No newline at end of file diff --git a/src/module/huge-base/DeptDetail.jsx b/src/module/huge-base/DeptDetail.jsx new file mode 100644 index 0000000..aeba659 --- /dev/null +++ b/src/module/huge-base/DeptDetail.jsx @@ -0,0 +1,99 @@ +/* eslint-disable */ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Form, Input, Button, Select, Spin } from 'antd'; +import fetch from '../../api/request' + +const FormItem = Form.Item; +const { TextArea } = Input; + + +class DeptDetail extends React.Component { + constructor(props) { + super(props) + this.state = { + spinning: true, + id: "", + dataSet: {} + } + } + + componentDidMount() { } + + handleSubmit = (e) => { // 提交表单数据 + e.preventDefault(); + this.props.form.validateFields((err, values) => { + if (err) return; + let obj = { + ...values, + id: this.props.params.id,//部门id + unitId: this.props.params.currentNode[0].id//单位编号 + } + //触发父级函数,调用保存接口 + this.props.saveFun(obj) + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + const { params, dataSet } = this.props; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + + return ( + <div className="deptdetail-main h-100"> + <Spin spinning={this.props.loading}> + <div> + <Form onSubmit={this.handleSubmit}> + <Card title={params.id == '' ? '部门新增' : '部门编辑'} bordered={false} + extra={<Row type="flex" gutter={20}> + <Col> + <Button onClick={this.props.cancelFun}>返回</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit" >确认</Button> + </Col> + </Row>} + > + <Row type="flex" > + <Col span={14}> + <FormItem label={"单位"} {...formItemLayout}> + <span>{params.currentNode[0].name}</span> + </FormItem> + </Col> + </Row> + <Row type="flex" > + <Col span={14}> + <FormItem label={"部门名称"} {...formItemLayout}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '请输入部门名称' }], + initialValue: dataSet.name || '', + })( + <Input placeholder="请输入部门名称" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex" > + <Col span={14}> + <FormItem label={"描述"} {...formItemLayout}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + ) + } +} + +const DeptDetailForm = Form.create()(DeptDetail); +export default DeptDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/FunctionDetail.jsx b/src/module/huge-base/FunctionDetail.jsx new file mode 100644 index 0000000..d60060b --- /dev/null +++ b/src/module/huge-base/FunctionDetail.jsx @@ -0,0 +1,104 @@ +import React from 'react'; +import { Card, Row, Col, Form, Input, Button, Spin } from 'antd'; + +const FormItem = Form.Item; +const { TextArea } = Input; + +class FunctionDetail extends React.Component { + constructor(props) { + super(props) + this.state = { + dataSet: {} + } + } + + handleSubmit = (e) => { // 提交表单数据 + e.preventDefault(); + this.props.form.validateFields((err, values) => { + console.log('提交表单数据:', values); + if (err) return; + let obj = { + ...values, + id: this.props.params.id, //编号 + moduleId: this.props.params.currentNode[0].id //模块编号 + } + this.props.saveFun(obj); + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + const { params, dataSet } = this.props; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + + return ( + <div className="functiondetail-main"> + <Spin spinning={this.props.loading}> + <div style={{ margin: 20 }}> + <Form onSubmit={this.handleSubmit}> + <Card title={params.id ? '功能信息(编辑)' : '功能信息(新增)'} bordered={false} + extra={ + <Row type="flex" gutter={20}> + <Col> + <Button onClick={this.props.cancelFun}>返回</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit">确认</Button> + </Col> + </Row> + } + > + <Row type="flex"> + <Col span={14}> + <FormItem label={"模块名称"} {...formItemLayout}> + <span>{this.props.params.currentNode[0].name}</span> + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={14}> + <FormItem label={"标识符"} {...formItemLayout}> + {getFieldDecorator('symbol', { + rules: [{ required: true, message: '请输入标识符' }], + initialValue: dataSet.symbol || '', + })( + <Input placeholder="请输入标识符" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={14}> + <FormItem label={"功能名称"} {...formItemLayout}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '请输入功能名称' }], + initialValue: dataSet.name || '', + })( + <Input placeholder="请输入功能名称" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={14}> + <FormItem label={"描述"} {...formItemLayout}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + ) + } +} + +const FunctionDetailForm = Form.create()(FunctionDetail); +export default FunctionDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/FunctionManage.jsx b/src/module/huge-base/FunctionManage.jsx new file mode 100644 index 0000000..e913c5d --- /dev/null +++ b/src/module/huge-base/FunctionManage.jsx @@ -0,0 +1,327 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import { Card, Row, Col, Icon, Form, message, Tree, Modal, Layout, Popconfirm, Divider, Spin, Button, Empty } from "antd"; +import moment from "moment"; +import SearchTree from '../../components/common/Tree'; +import SearchFormView from '../../components/common/SearchFormView'; +import TableView from '../../components/common/TableView'; +import FunctionDetail from './FunctionDetail';//功能详情 +import fetch from '../../api/request'; + +const FormItem = Form.Item; +const confirm = Modal.confirm; +const TreeNode = Tree.TreeNode; + +class FunctionManage extends React.Component { + constructor(props) { + super(props); + this.state = { + resourceList: [], + treeKey: Date.now(), + expandedKeys: [], + tableData: [], + totalElements: 1, + pageSize: 10, + page: 1, + + treeData: [], + leafNodes: [], + currentNode: [], + rightShow: false, + modify: false, + parentId: "", + id: "", + dataSet: {}, + selectedKeys: [], + treeLoading: false,//左侧树结构loading + loading: false,//部门详情的loading + formData: { + __key: Date.now(), + page: 1, + size: 10, + } + }; + } + componentDidMount() { + this.loadData(); + } + + //加载左侧树形数据 + loadData = () => { + this.setState({ treeLoading: true }); + fetch({ + url: `api/module/getAllModulesByTree` + }).then(res => { + this.setState({ treeLoading: false }); + if (res) { + res = this.handleTreeData(res); + this.setState({ treeData: res, treeKey: Date.now() }) + } + }) + }; + + //处理树形数据结构 + handleTreeData = data => { + for (let i = 0; i < data.length; i++) { + const node = data[i]; + node.key = node.id; + node.title = node.name; + if (data[i].modules) { + data[i].children = data[i].modules; + this.handleTreeData(node.children); + } + if (data[i].children) { + this.handleTreeData(node.children); + } + // else{ + // this.handleTreeData([node]) + // } + } + return data; + }; + + //点击树形节点触发函数 + treeSelect = (tableData, currentNode) => { + console.log(tableData, currentNode); + if (currentNode[0].children && currentNode[0].children.length > 0) { + message.error("请选择下级的节点"); + this.setState({ + rightShow: false + }); + return; + } else { + message.success("已选择:" + currentNode[0].name); + } + this.setState( + { + leafNodes: tableData, + currentNode, + unitLocation: currentNode[0].name, + parentId: currentNode[0].parentId, + selectedKeys: [currentNode[0].id] + }, + () => { + this.loadTableData(); + } + ); + }; + + //加载右侧table表格数据 + loadTableData = () => { + const { currentNode, formData } = this.state; + if (currentNode[0].length < 0) { + message.error("请选择左边节点后进行查询操作"); + return; + } + this.setState({ + rightShow: true, + formData: { + ...formData, + __key: Date.now(), + moduleId: currentNode[0].id + } + }) + }; + + //功能(新增 | 编辑),详情接口 + modifyFun = id => { + this.setState({ + modify: true, + id, + dataSet: {} + }); + if (id) { + this.setState({ loading: true }); + fetch({ + url: `api/function/getById`, + params: { id } + }).then(res => { + this.setState({ loading: false }); + if (res) { + this.setState({ dataSet: res }) + } + }) + } + }; + + clearKeys = () => { + let _this = this; + _this.setState({ + currentNode: [], + rightShow: false + }); + }; + + cancelFun = () => { + this.setState({ + modify: false + }); + }; + + //保存表单(确定按钮) + saveFun = data => { + this.setState({ loading: true }); + fetch({ + url: `api/function/save`, + method: 'POST', + data + }).then(res => { + this.setState({ loading: false }); + if (res) { + message.success("保存功能成功"); + this.setState({ modify: false }); + this.loadTableData();//重新加载表格table数据 + } + }) + }; + + onExpand = expandedKeys => { + this.setState({ + expandedKeys + }); + }; + + onSelect = selectedKeys => { + this.setState({ + selectedKeys + }); + }; + + //删除功能 + delete = id => { + let _this = this; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该功能吗?</span>, + onOk() { + fetch({ + url: `api/function/delete`, + params: { ids: id } + }).then(res => { + if (res) { + message.success("删除成功"); + _this.loadTableData(); + } + }) + }, + onCancel() { } + }); + }; + + setFormData = data => { + console.log('form', data); + this.setState({ + formData: data, + }); + } + + renderColumns = () => { + return [ + { title: "功能名称", dataIndex: "name" }, + { title: "标识符", dataIndex: "symbol", ellipsis: true }, + { title: "功能描述", dataIndex: "description", ellipsis: true }, + { title: "创建时间", dataIndex: "updateTime", render: (text, record) => (text && moment(text).format("YYYY-MM-DD HH:mm")) }, + { + title: "操作", key: "operation", render: (text, record) => { + return ( + <div> + <a onClick={() => this.modifyFun(record.id)}>修改</a> + <Divider type="vertical" /> + <a onClick={() => this.delete(record.id)}>删除</a> + </div> + ); + } + } + ]; + }; + + render() { + const { treeKey, treeData, rightShow, treeLoading, formData, currentNode } = this.state; + + const params = { + id: this.state.id, + currentNode + }; + + let tableParams = { + url: `api/function/query`, + formData, + key: formData.__key, + columns: this.renderColumns(), + extraFromData: { + moduleId: currentNode.length ? currentNode[0].id : '' + }, + setFormData: this.setFormData + } + + return ( + <div className="functionmanage-main h-100 padding margin bg-white"> + {!this.state.modify && ( + <React.Fragment> + <div className="padding h-100"> + <Row style={{ height: "100%" }}> + <Col + span={8} + style={{ border: "1px solid #e8e8e8", padding: 10 }} + className="h-100" + > + <Spin spinning={treeLoading}> + <SearchTree + key={treeKey} + data={treeData} + onExpand={this.onExpand} + expandedKeys={this.state.expandedKeys} + treeSelect={this.treeSelect} + clearKeys={this.clearKeys} + onSelect={this.onSelect} + selectedKeys={this.state.selectedKeys} + /> + </Spin> + </Col> + <Col span={1} /> + <Col + span={15} + style={{ border: "1px solid #e8e8e8", padding: 10 }} + className="h-100" + > + { + rightShow && ( + <div> + <SearchFormView data={[{ type: 'input', name: '功能名称', label: '功能名称', key: 'name' }]} width={'50%'} formData={formData} setFormData={this.setFormData} width={'50%'}/> + <Row className="margin-bottom"> + <Col> + <Button onClick={() => this.modifyFun('')} type="primary" className="button-do"> + 新增 + </Button> + </Col> + </Row> + <TableView {...tableParams} /> + </div> + )} + { + !rightShow && ( + <Empty description={'暂无数据,请点击左侧树形结构'} className="h-100 flex-box-column align-center justify-content" /> + )} + </Col> + </Row> + </div> + </React.Fragment> + )} + + {this.state.modify && ( + <FunctionDetail + cancelFun={this.cancelFun} + params={params} + dataSet={this.state.dataSet} + saveFun={this.saveFun} + loading={this.state.loading} + /> + )} + </div> + ); + } + + +} + +const FunctionManageList = Form.create()(FunctionManage); +export default FunctionManageList; diff --git a/src/module/huge-base/GroupDetail.jsx b/src/module/huge-base/GroupDetail.jsx new file mode 100644 index 0000000..0f93c44 --- /dev/null +++ b/src/module/huge-base/GroupDetail.jsx @@ -0,0 +1,150 @@ +/* eslint-disable */ +import React from 'react'; +import { Card, Row, Col, Form, Input, Button, Select, message, Spin } from 'antd'; +import { createHashHistory } from 'history' +import fetch from '../../api/request' + +const history = createHashHistory(); +const { TextArea } = Input; +const FormItem = Form.Item; +const Option = Select.Option; + +class GroupDetail extends React.Component { + constructor(props) { + super(props) + this.id = props.match.params.id == 'new' ? '' : props.match.params.id; + this.flag = props.match.params.flag == 'Modify' ? '修改' : '新增'; + this.state = { + spinning: false, + dataSet: {} + } + } + + componentDidMount() { + if (this.id) { + this.setState({ spinning: true }); + fetch({ + url: `api/group/getById`, + params: { id: this.id } + }).then(res => { + this.setState({ spinning: false }); + if (res) { + this.setState({ dataSet: res }); + } + }) + } + } + + // 返回 + goBack = () => { + history.goBack(); + } + + // 确定 + handleSubmit = (e) => { + e.preventDefault(); + this.props.form.validateFields((err, values) => { + if (err) return; + this.setState({ spinning: true }); + fetch({ + url: `api/group/save`, + method: 'POST', + data: { + ...this.state.dataSet, + ...values + } + }).then(res => { + this.setState({ spinning: false }); + message.success("保存组成功"); + history.goBack(); + }) + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + const { dataSet } = this.state; + + const formItemLayout1 = { + labelCol: { xs: { span: 24 }, sm: { span: 10 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 14 }, }, + }; + const formItemLayout2 = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + + return ( + <div className="groupdetail-main margin padding bg-white"> + + <Spin spinning={this.state.spinning}> + <div style={{ margin: 20 }}> + <Form onSubmit={this.handleSubmit}> + + <Card title={this.id ? '基础信息(编辑)' : '基础信息(新增)'} bordered={false} extra={ + <Row type="flex" gutter={20}> + <Col> + <Button onClick={this.goBack}>返回</Button> + </Col> + <Col> + <Button htmlType="submit" type="primary">确定</Button> + </Col> + </Row> + }> + <Row type="flex"> + <Col span={8}> + <FormItem label={"标识符"} {...formItemLayout1}> + {getFieldDecorator('symbol', { + rules: [{ required: true, message: '标识符必填' }], + initialValue: dataSet.symbol || '', + })( + <Input placeholder="请输入标识符" /> + )}</FormItem> + </Col> + <Col span={8}> + <FormItem label={"组名称"} {...formItemLayout1}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '组名称必填' }], + initialValue: dataSet.name || '' + })( + <Input placeholder="请输入组名称" /> + )}</FormItem> + </Col> + </Row> + <Row> + <Col span={8}> + <FormItem label={"组类型"} {...formItemLayout1}> + {getFieldDecorator('groupType', { + rules: [{ required: true, message: '组类型必选' }], + initialValue: dataSet.groupType || undefined + })( + <Select style={{ width: '100%' }} placeholder="请选择" allowClear> + <Option value={1}>用户类型</Option> + <Option value={2}>角色类型</Option> + <Option value={3}>资源类型</Option> + </Select> + )}</FormItem> + </Col> + </Row> + <Row> + <Col span={16}> + <FormItem label={"描述"} {...formItemLayout2}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description || '' + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + ) + } +} + +const GroupDetailForm = Form.create()(GroupDetail); +export default GroupDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/GroupManage.jsx b/src/module/huge-base/GroupManage.jsx new file mode 100644 index 0000000..03d8b0b --- /dev/null +++ b/src/module/huge-base/GroupManage.jsx @@ -0,0 +1,121 @@ +/* eslint-disable */ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Row, Col, Icon, Button, message, Modal, Divider } from 'antd'; +import TableView from '../../components/common/TableView'; +import SearchFormView from '../../components/common/SearchFormView'; +import moment from 'moment'; +import fetch from '../../api/request'; + +const confirm = Modal.confirm; + +export default class GroupManage extends React.Component { + constructor(props) { + super(props); + this.state = { + formData: { + __key: Date.now(), + page: 1, + size: 10, + }, + }; + } + + componentDidMount() { } + + setFormData = data => { + this.setState({ + formData: data, + }); + } + + renderColumns = () => { + let obj = this; + return [ + { title: '标识符', className: "txt-c", dataIndex: 'symbol' }, + { title: '组名称', className: "txt-c", dataIndex: 'name' }, + { title: '组类型', className: "txt-c", dataIndex: 'groupType', render: (text, record) => text == "1" ? "用户类型" : text == "2" ? "角色类型" : text == "3" ? "资源类型" : "" }, + { title: '描述', className: "txt-c", dataIndex: 'description', render: (text, record) => text == null ? text : (text.length <= 20 ? text : (text.substring(0, 20) + '...')) }, + { title: '创建时间', className: "txt-c", dataIndex: 'createTime', render: (text, record) => text !== "" && text != null ? moment(text).format("YYYY-MM-DD HH:mm") : "" }, + { + title: '操作', className: "txt-c", key: 'operation', render: (text, record) => { + return <div> + <Link to={{ pathname: "/baseManage/group/Detail/" + record.id + '/Modify', query: { id: record.id } }}>修改</Link> + <span> | </span> + <a onClick={() => this.delete(record.id)}>删除</a> + </div> + } + } + ] + } + + // 新增组 + add = () => { + this.props.history.push('/baseManage/group/Detail/new/Add') + } + + //删除组 + delete = (id) => { + let _this = this + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该组吗?</span>, + content: <span style={{ fontSize: 18 }}>删除该组的同时,会删除与该组的所有关系。</span>, + onOk() { + fetch({ + url: `api/group/delete`, + params: { + ids: id + } + }).then(res => { + if (res) { + message.success("删除成功"); + _this.setState({ + formData: { + ..._this.state.formData, + __key: Date.now() + } + }) + } + }) + }, + onCancel() { }, + }); + } + + render() { + const { formData } = this.state; + let tableParams = { + url: `api/group/query`, + formData, + key: formData.__key, + columns: this.renderColumns(), + extraFromData: {}, + setFormData: this.setFormData + } + return ( + <div className="groupmanage-main margin padding bg-white"> + <SearchFormView + formData={formData} + setFormData={this.setFormData} + data={[ + { type: 'input', name: '标识符', label: '标识符', key: 'symbol' }, + { type: 'input', name: '组名称', label: '组名称', key: 'name' }, + { + type: 'select', name: '组类型', label: '组类型', key: 'groupType', list: [ + { name: 0, value: '全部' }, + { name: 1, value: '用户类型' }, + { name: 2, value: '角色类型' }, + { name: 3, value: '资源类型' }, + ] + }, + ]} /> + <Row type="flex" gutter={20} className="margin-bottom"> + <Col> + <Button type="primary" onClick={this.add}>新增组</Button> + </Col> + </Row> + <TableView {...tableParams} /> + </div> + ) + } +} diff --git a/src/module/huge-base/HeaderCustom.jsx b/src/module/huge-base/HeaderCustom.jsx new file mode 100644 index 0000000..0d99d17 --- /dev/null +++ b/src/module/huge-base/HeaderCustom.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Layout } from 'antd'; +import data from '../data/menu'; +import HeaderCustom from '../component/HeaderCustom'; + +export default class Menu extends React.Component { + constructor(props) { + super(props); + this.state = { + collapsed: false + } + } + render() { + return ( + <HeaderCustom /> + ) + } +} diff --git a/src/module/huge-base/JobDetail.jsx b/src/module/huge-base/JobDetail.jsx new file mode 100644 index 0000000..f1a6df8 --- /dev/null +++ b/src/module/huge-base/JobDetail.jsx @@ -0,0 +1,122 @@ +import React from 'react'; +import { Card, Row, Col, Icon, Form, Input, Button, Select, Table, DatePicker, message, Breadcrumb, Spin, Layout, Upload, Modal } from 'antd'; + +const { TextArea } = Input; +const FormItem = Form.Item; +const Option = Select.Option; +const ButtonGroup = Button.Group; + +class JobDetail extends React.Component { + constructor(props) { + super(props) + this.state = { + + } + } + + handleSubmit = (e) => { // 提交表单数据 + e.preventDefault(); + this.props.form.validateFields((err, values) => { + console.log('提交表单数据:', values); + if (err) return; + let obj = { + ...values, + id: this.props.params.id || '', //岗位id + unitId: this.props.params.unitId, //单位id + } + this.props.saveFun(obj); + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + const { dataSet, params } = this.props; + console.log(dataSet) + + return ( + <div className="jobdetail-main h-100 margin padding bg-white"> + <Spin spinning={this.props.spinning}> + <div> + <Form onSubmit={this.handleSubmit}> + <Card title={params.postId ? '岗位信息(编辑)' : '岗位信息(新增)'} bordered={false} extra={ + <Row type="flex" gutter={20}> + <Col> + <Button onClick={this.props.cancelFun}>返回</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit" >确定</Button> + </Col> + </Row> + }> + <Row type="flex"> + <Col span={13}> + <FormItem label={"岗位名称"} {...formItemLayout}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '请输入岗位名称' }], + initialValue: dataSet.name || '', + })( + <Input placeholder="请输入岗位名称" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={13}> + <FormItem label={"岗位级别"} {...formItemLayout}> + {getFieldDecorator('level', { + initialValue: dataSet.level || undefined + })( + <Select placeholder="请选择岗位级别"> + <Option value={1}>厅级</Option> + <Option value={2}>处级</Option> + <Option value={3}>科级</Option> + </Select> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={13}> + <FormItem label={"所属部门"} {...formItemLayout}> + {getFieldDecorator('deptId', { + rules: [{ required: true, message: '所属部门' }], + initialValue: dataSet.deptId || undefined + })( + <Select placeholder="请选择所属部门"> + { + params.depts.map((item, idx) => { + return ( + <Option value={item.id} key={item.id}>{item.name}</Option> + ) + }) + } + </Select> + )}</FormItem> + </Col> + </Row> + + <Row type="flex"> + <Col span={13}> + <FormItem label={"岗位描述"} {...formItemLayout}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description + })( + <TextArea placeholder="请输入备注" rows={5} /> + )}</FormItem> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + ) + } +} + +// const SHOW_PARENT = TreeSelect.SHOW_PARENT; +const JobDetailForm = Form.create()(JobDetail); +export default JobDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/JobManage.jsx b/src/module/huge-base/JobManage.jsx new file mode 100644 index 0000000..dd1b5c5 --- /dev/null +++ b/src/module/huge-base/JobManage.jsx @@ -0,0 +1,566 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import { Card, Row, Col, Icon, Form, Input, Button, Table, DatePicker, message, Breadcrumb, Tree, Modal, Layout, Popconfirm, Select, Cascader, Spin, Alert, Tooltip, Empty, Statistic, Dropdown, Menu, Tag } from "antd"; +import moment from "moment"; +import SearchTree from '../../components/common/Tree'; +import fetch from '../../api/request'; +// import SearchTree from "../component/tree/index"; +// import Fetch from "../fetch"; +import JobDetail from "./JobDetail"; +// import { +// getUnitByAssociate, +// getUserOfPost, +// jobCount, +// postSet, +// getPostDetail, +// savePost +// } from "../fetch/api"; + +const FormItem = Form.Item; +const confirm = Modal.confirm; +const TreeNode = Tree.TreeNode; +const Search = Input.Search; + +class JobManage extends React.Component { + constructor(props) { + super(props); + this.state = { + options: [], + selectOptionId: "", + spinning: false, + dataSet: {}, + jobCount: {}, + user: {}, + + jobData: [], + selectUser: {}, //右边选中的user + selectUserLeft: {}, //左边选中的user + visible: false, + tsData: {}, //临时数据 + + // unitId: '' //单位编号 + showUnder: false, + modify: false, //是否切换详情 + params: { + postId: "", //岗位id + unitId: "", //所选的单位id + depts: [] //单位下的部门所有信息 + }, + + detailData: {}, //详情数据, + getUnitByAssociate: null,//部门下的岗位分配情况 + searchCode: '',//模糊查询字符串 + + currentSelectUnMatchUsers: null,//当前所选未配岗人员 + + }; + } + componentDidMount() { + this.getAllUnits(); + } + + //获取所有的单位树形结构 + getAllUnits = () => { + fetch({ + url: 'api/unit/getAllUnitsByCascade' + }).then(res => { + if (res) { + this.setState({ options: res }) + } + }) + } + + //级联框onChange事件 + onChange = (value, selectedOptions) => { + this.setState({ + selectOptionId: selectedOptions.length && selectedOptions[selectedOptions.length - 1].id, + }, () => { + if (this.state.selectOptionId) { this.loadJobData() } + else { this.setState({ showUnder: false }) } + }); + }; + + // 加载关于岗位的相关接口 + loadJobData = () => { + this.setState({ + spinning: true + }); + let p = [this.jobCount(), this.getUnitByAssociate(), this.getUserOfPost()] + Promise.all(p).then(res => { + this.setState({ spinning: false }); + if (res.length == p.length) { + this.setState({ + showUnder: true, + jobCount: res[0], + getUnitByAssociate: res[1], + getUserOfPost: res[2] + }) + } + }) + }; + + // 获取单位相关数据(包含单位下的部门,部门下的岗位) + getUnitByAssociate = () => { + let { selectOptionId } = this.state;//单位id + return new Promise((resolve, reject) => { + fetch({ + url: `api/unit/getUnitByAssociate`, + params: { id: selectOptionId } + }).then(res => { + if (res) { + resolve(res); + } + }) + }) + } + + //获取配岗用户 + getUserOfPost = () => { + return new Promise((resolve, reject) => { + fetch({ + url: `api/user/getUserOfPost` + }).then(res => { + if (res) { + resolve(res); + } + }) + }) + } + + // 获取岗位统计数 + jobCount = () => { + let { selectOptionId } = this.state;//单位id + return new Promise((resolve, reject) => { + fetch({ + url: `api/post/count`, + params: { unitId: selectOptionId } + }).then(res => { + if (res) { + resolve(res); + } + }) + }) + } + + //从左侧选择员工(兼岗、调岗、撤岗) + selectLeft = e => { + document.querySelector("body").style.cursor = "crosshair"; + }; + + + cancelFun = () => { + this.setState({ + modify: false + }); + }; + + //兼岗 + setJG = () => { + let { dgOrjgData, currentSelectUnMatchUsers } = this.state; + fetch({ + url: `api/post/set`, + method: 'POST', + data: { + operateType: 2, + userId: currentSelectUnMatchUsers.id,//员工id + sourcePostId: dgOrjgData.id//岗位id + } + }).then(res => { + if (res) { + message.success('设置兼岗成功'); + this.setState({ visible: false, currentSelectUnMatchUsers: null }) + this.loadJobData(); + } + }) + }; + + //调岗 + setDG = () => { + let { dgOrjgData, currentSelectUnMatchUsers } = this.state; + fetch({ + url: `api/post/set`, + method: 'POST', + data: { + operateType: 3, + userId: currentSelectUnMatchUsers.id, + sourcePostId: currentSelectUnMatchUsers.postId, + targetPostId: dgOrjgData.id + } + }).then(res => { + if (res) { + message.success('设置调岗成功'); + this.setState({ visible: false, currentSelectUnMatchUsers: null }) + this.loadJobData(); + } + }) + }; + + //撤岗 + setCG = (data) => { + let _this = this; + let { currentSelectUnMatchUsers } = _this.state; + confirm({ + title: `你确定要对员工(${data.userTrueName})撤岗吗?`, + onOk() { + fetch({ + url: `api/post/set`, + method: 'POST', + data: { + operateType: 4, + userId: data.userId,//员工id + sourcePostId: data.id//岗位id + } + }).then(res => { + if (res) { + message.success('撤岗成功'); + _this.loadJobData(); + if (currentSelectUnMatchUsers && currentSelectUnMatchUsers.id == data.userId) { + _this.setState({ currentSelectUnMatchUsers: null })//取消其高亮显示 + } + } + }) + }, + onCancel() { }, + }); + }; + + //右侧选中员工,进行配岗操作 + setPG = (post) => { + let _this = this; + let { currentSelectUnMatchUsers, getUnitByAssociate } = _this.state; + if (!currentSelectUnMatchUsers) { + return message.warning('请于右侧待配岗员工列表中选择待岗员工') + } + + if (getUnitByAssociate && getUnitByAssociate.depts.reduce((p, n) => ( + n.posts ? p.concat(n.posts) : p + ), []).findIndex(({ userId }) => userId == currentSelectUnMatchUsers.id) !== -1) { + // 此处触发调岗、兼岗操作 + return _this.setState({ visible: true, dgOrjgData: post }); + } + confirm({ + title: `已选择员工(${currentSelectUnMatchUsers.trueName}), 您确定要对该员工配岗吗?`, + onOk() { + fetch({ + url: `api/post/set`, + method: 'POST', + data: { + operateType: 1, //设置主岗 + sourcePostId: post.id, + userId: currentSelectUnMatchUsers.id, + userTrueName: currentSelectUnMatchUsers.trueName + } + }).then(res => { + if (res) { + message.success('配岗成功'); + _this.setState({ currentSelectUnMatchUsers: null }); + _this.loadJobData(); + } + }) + + }, + onCancel() { }, + }); + } + + // 员工的模糊搜索 + onInputChange = (e) => { + this.setState({ searchCode: e.target.value }) + } + + onCancel = () => { + this.setState({ + visible: false + }); + }; + + // 岗位(新增 | 编辑) + modifyFun = (data) => { + let { getUnitByAssociate } = this.state; + let { id } = data; + this.setState({ + modify: true, + params: { + ...data, + depts: getUnitByAssociate.depts + } + }); + if (id) { + this.setState({ spinning: true }); + fetch({ + url: `api/post/getById`, + params: { id } + }).then(res => { + if (res) { + this.setState({ + detailData: res, + spinning: false, + }) + } + }) + } else { + this.setState({ + detailData: {}//置空表单数据 + }) + } + }; + + //保存岗位 + saveFun = data => { + this.setState({ spinning: true }); + fetch({ + url: `api/post/save`, + method: 'POST', + data + }).then(res => { + this.setState({ spinning: false }); + if (res) { + message.success("保存岗位成功"); + this.setState({ modify: false }); + this.loadJobData(); + } + }) + }; + + //删除岗位 + postDel = (data) => { + let _this = this; + let { id, name } = data; + confirm({ + title: `您确定要删除岗位(${name})吗?`, + onOk() { + fetch({ + url: `api/post/delete`, + params: { ids: id } + }).then(res => { + if (res) { + message.success('删除岗位成功'); + _this.loadJobData(); + } + }) + }, + onCancel() { }, + }); + } + + // 选中当前待配岗人员 + setCurrentSelectUnMatchUsers = (person) => { + let { currentSelectUnMatchUsers } = this.state; + currentSelectUnMatchUsers = currentSelectUnMatchUsers && person.id == currentSelectUnMatchUsers.id ? null : person; + if (currentSelectUnMatchUsers) { + message.success('已选中:' + currentSelectUnMatchUsers.trueName) + } + this.setState({ + currentSelectUnMatchUsers + }) + } + + render() { + const { options, jobCount, visible, params, getUnitByAssociate, searchCode, getUserOfPost, currentSelectUnMatchUsers } = this.state; + + const gridStyle = { width: '25%', padding: 8, boxShadow: 'none' }; + + return ( + <React.Fragment> + <div + className="h-100 border padding bg-white" + style={{ display: !this.state.modify ? "flex" : "none" }} + > + <React.Fragment> + {visible && ( + <Modal + onCancel={this.onCancel} + visible={true} + footer={ + <div> + <Button onClick={this.setJG} type="primary">兼岗</Button> + <Button onClick={this.setDG} type="primary">调岗</Button> + <Button onClick={this.onCancel}>取消</Button> + </div> + } + > + <p>您已经对此员工进行配岗,你还可以对他进行</p> + </Modal> + )} + <div + style={{ + width: '100%', + display: "flex", + flexDirection: "column", + overflowY: "auto" + }} + > + {/* 单位级联框 */} + <div className="padding-tb"> + <Cascader + fieldNames={{ + label: "name", + value: "name", + children: "children" + }} + options={options} + onChange={this.onChange} + placeholder="请选择单位" + style={{ width: "100%" }} + changeOnSelect + /> + </div> + + <div className="flex-1"> + <Spin spinning={this.state.spinning}> + {this.state.showUnder && ( + <React.Fragment> + <Row style={{ height: "100%" }}> + <Col + span={15} + style={{ border: "1px solid #e8e8e8", display: 'flex', flexDirection: 'column', padding: 10 }} + className="h-100 treeNodeUnselectable" + > + {/* 当前单位的配岗信息 */} + <Row type="flex" justify="space-between" gutter={20}> + <Col> + <Row type="flex" gutter={30} style={{ marginBottom: 15 }}> + <Col> + <div className="flex-box align-center"> + <a className="statistic-label">总岗位:</a> + <Statistic value={jobCount.totalNum || 0} valueStyle={{ fontSize: 16, fontWeight: 'bold' }} /> + </div> + </Col> + <Col> + <div className="flex-box align-center"> + <div className="statistic-label">实岗:</div> + <Statistic value={jobCount.fullNum || 0} valueStyle={{ fontSize: 16, fontWeight: 'bold' }} /> + </div> + </Col> + <Col> + <div className="flex-box align-center"> + <div className="statistic-label">空岗:</div> + <Statistic value={jobCount.emptyNum || 0} valueStyle={{ fontSize: 16, fontWeight: 'bold' }} /> + </div> + </Col> + </Row> + </Col> + <Col> + <Button type='primary' size="small" onClick={() => { this.modifyFun({ id: '' }) }}>新增岗位</Button> + </Col> + </Row> + + <div className="flex-1"> + { + getUnitByAssociate && getUnitByAssociate.depts && getUnitByAssociate.depts.map(({ posts, name, id }, deptIndex) => ( + <Card type="inner" title={'部门:' + name} style={{ marginBottom: 15 }} size="small" key={id}> + { + posts && posts.length > 0 ? posts.map((p, posIndex) => ( + <Card.Grid style={gridStyle} hoverable={false} key={p.id}> + <Row type="flex" gutter={10}> + <Col> + {/* 岗位名(编辑,删除) */} + <Dropdown overlay={<Menu> + <Menu.Item key="1" onClick={() => this.modifyFun(p)}>编辑岗位</Menu.Item> + <Menu.Item key="2" onClick={() => this.postDel(p)}>删除岗位</Menu.Item> + </Menu>} trigger={['contextMenu']}> + <div style={{ cursor: 'pointer' }} >{p.name}</div> + </Dropdown> + </Col> + {p.userTrueName && + <Col> + <Dropdown overlay={<Menu> + <Menu.Item key="1" onClick={() => this.setCG({ ...p, deptIndex, posIndex })}>撤岗</Menu.Item> + </Menu>} trigger={['contextMenu']}> + {/* <a>{p.userTrueName}</a> */} + {currentSelectUnMatchUsers && currentSelectUnMatchUsers.id == p.userId ? + <Tag style={{ cursor: 'pointer' }} color="#cc4e45" onDoubleClick={() => this.setCurrentSelectUnMatchUsers({ id: p.userId, trueName: p.userTrueName, postId: p.id })}>{p.userTrueName}</Tag> : + <a onDoubleClick={() => this.setCurrentSelectUnMatchUsers({ id: p.userId, trueName: p.userTrueName, postId: p.id })}>{p.userTrueName}</a> + } + </Dropdown> + </Col>} + {!p.userTrueName && <Col><a onClick={() => { this.setPG(p) }}>[ 请选择 ]</a></Col>} + </Row> + </Card.Grid> + )) : <Row type="flex" justify="center"> + <Col>该 部 门 下 暂 无 岗 位</Col> + </Row> + } + </Card> + )) + } + </div> + + <Row> + <Alert message="您可以右键点击‘岗位’进行岗位编辑、删除,双击人员选中该人员,对该人员进行配岗操作" type="warning" /> + </Row> + </Col> + <Col span={1} /> + <Col + span={8} + style={{ + border: "1px solid #e8e8e8", + display: "flex", + flexDirection: "column", + overflow: 'auto', + padding: 10 + }} + className="h-100 treeNodeUnselectable" + > + <div style={{ fontSize: 16, fontWeight: 'bold', textAlign: 'center', paddingBottom: 10 }}> + 待配岗人员 + </div> + <Input + style={{ marginBottom: 1 }} + placeholder="请输入人员姓名" + onChange={this.onInputChange} + allowClear + prefix={<Icon type="search" />} + /> + <div className="flex-1"> + <Card bordered={false} bodyStyle={{ padding: 10 }}> + { + getUserOfPost && getUserOfPost.unMatchUsers && getUserOfPost.unMatchUsers.length > 0 ? + getUserOfPost.unMatchUsers.filter(({ trueName }) => trueName.indexOf(searchCode) !== -1).map((person) => ( + <Card.Grid style={{ ...gridStyle, width: '20%' }} key={person.id}> + {currentSelectUnMatchUsers && currentSelectUnMatchUsers.id == person.id ? + <Tag style={{ cursor: 'pointer' }} color="#cc4e45" onDoubleClick={() => this.setCurrentSelectUnMatchUsers(person)}>{person.trueName}</Tag> : + <Tag style={{ cursor: 'pointer' }} onDoubleClick={() => this.setCurrentSelectUnMatchUsers(person)}>{person.trueName}</Tag> + } + </Card.Grid> + )) : <Empty description={'暂无待配岗人员'} className="h-100 flex-box-column align-center justify-content" /> + } + </Card> + + </div> + <div style={{ marginTop: 10 }}> + <Row> + <Alert message="您可以双击人员选中未配岗人员,对该人员进行配岗操作" type="warning" /> + </Row> + </div> + </Col> + </Row> + <Row /> + </React.Fragment> + )} + + {!this.state.showUnder && ( + <Empty description={'暂无数据,请选择单位'} className="h-100 flex-box-column align-center justify-content" /> + )} + </Spin> + </div> + </div> + </React.Fragment> + </div> + + <div style={{ display: this.state.modify ? "block" : "none" }}> + <JobDetail + cancelFun={this.cancelFun} + params={params} + dataSet={this.state.detailData} + saveFun={this.saveFun} + spinning={this.state.spinning} + /> + </div> + </React.Fragment> + ); + } +} + +const JobManageList = Form.create()(JobManage); +export default JobManageList; diff --git a/src/module/huge-base/Menu.jsx b/src/module/huge-base/Menu.jsx new file mode 100644 index 0000000..6493c7d --- /dev/null +++ b/src/module/huge-base/Menu.jsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { Layout } from 'antd'; + +import TreeMenu from '../component/TreeMenu'; +import data from '../data/menu'; +const { Sider } = Layout; +function find(data, pathname) { + for (const { path, children } of data) { + if (path === pathname) return path; + if (children) { + const result = find(children, pathname); + if (result) return result; + } + } + return null; +} + +function selected(data, pathname) { + if (!pathname || pathname === '/') return pathname; + return find(data, pathname) || selected(data, pathname.split('/').slice(0, -1).join('/')); +} + +export default class Menu extends React.Component { + constructor(props) { + super(props); + this.state = { + collapsed: false + } + } + onCollapse = collapsed => { + this.setState({ collapsed }); + } + render() { + const pathname = selected(data, this.props.location.pathname); + let defaultOpenKeys = (data.find(node => node.children && node.children.find(child => child.path == pathname)) || {}).name + return ( + <Sider onCollapse={this.onCollapse} + collapsed={this.state.collapsed} + className="sider-light" + breakpoint="lg" + collapsible={false} + > + <TreeMenu + data={data} + defaultOpenKeys={[(data.find(node => node.children && node.children.find(child => child.path == pathname)) || {}).name]} + defaultSelectedKeys={[pathname]} + /> + </Sider> + ) + } +} diff --git a/src/module/huge-base/ModuleDetailEdit.jsx b/src/module/huge-base/ModuleDetailEdit.jsx new file mode 100644 index 0000000..3be8c48 --- /dev/null +++ b/src/module/huge-base/ModuleDetailEdit.jsx @@ -0,0 +1,209 @@ +import React from 'react'; +import { Card, Row, Col, Icon, Form, Input, Button, Spin, Modal, Radio } from 'antd'; + +const { TextArea } = Input; +const FormItem = Form.Item; +const RadioButton = Radio.Button; +const RadioGroup = Radio.Group; + +class ModuleDetailEdit extends React.Component { + constructor(props) { + super(props) + // this.id = props.match.params.id; + // this.flag = props.match.params.flag == 'Modify' ? '修改' : '新增'; + this.state = { + spinning: false, + id: '', + parentId: '', + dataSet: {}, + } + } + + componentDidMount() { } + + //提交表单数据(保存) + handleSubmit = (e) => { + e.preventDefault(); + this.props.form.validateFields((err, values) => { + console.log('提交表单数据:', values); + if (err) return; + //触发父级保存接口函数 + this.props.saveFun(values); + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + const { dataSet, params, loading } = this.props; + + return ( + <div> + { + this.props.edit == 'true' ? + <div> + <Spin spinning={loading}> + + <div> + <Form onSubmit={this.handleSubmit}> + <Card title={params.id ? '模块信息(编辑)' : '模块信息(新增)'} bordered={false}> + <Row type="flex"> + <Col span={16}> + <FormItem label={"资源类型"} {...formItemLayout}> + {getFieldDecorator('isMenu', { + rules: [{ required: true, message: '资源类型必选' }], + initialValue: dataSet.isMenu + })( + <RadioGroup> + <RadioButton value={1}>菜单</RadioButton> + <RadioButton value={0}>模块</RadioButton> + </RadioGroup> + )} + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"标识符"} {...formItemLayout}> + {getFieldDecorator('symbol', { + rules: [{ required: true, message: '请输入标志符' }], + initialValue: dataSet.symbol || '', + })( + <Input placeholder="请输入标识符" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"资源名称"} {...formItemLayout}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '请输入资源名称' }], + initialValue: dataSet.name || '', + })( + <Input placeholder="请输入资源名称" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"路径"} {...formItemLayout}> + {getFieldDecorator('url', { + rules: [{ required: true, message: '请输入路径' }], + initialValue: dataSet.url || '', + })( + <Input /> + )} + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"路径设置"} {...formItemLayout}> + {getFieldDecorator('urlType', { + rules: [{ required: true, message: '路径类型必选' }], + initialValue: dataSet.urlType || undefined + })( + <RadioGroup> + <RadioButton value={1}>相对路径</RadioButton> + <RadioButton value={0}>绝对路径</RadioButton> + </RadioGroup> + )} + </FormItem> + </Col> + </Row> + + <Row type="flex"> + <Col span={16}> + <FormItem label={"描述"} {...formItemLayout}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description || '' + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + <Row type="flex" gutter={20} style={{ width: '75%' }} justify="center"> + <Col> + <Button onClick={this.props.cancelFun}>取消</Button> + </Col> + <Col> + <Button className="button-do" htmlType="submit" type="primary">保存</Button> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + : + <div> + <Spin spinning={loading}> + <div> + <Form onSubmit={this.props.editFun}> + <Card title={'模块信息'} bordered={false}> + <Row type="flex"> + <Col span={16}> + <FormItem label={"资源类型"} {...formItemLayout}> + {dataSet.isMenu == 1 && '菜单'} + {dataSet.isMenu == 0 && '模块'} + + </FormItem> + </Col> + </Row> + + <Row type="flex"> + <Col span={16}> + <FormItem label={"标识符"} {...formItemLayout}> + {dataSet.symbol} + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"资源名称"} {...formItemLayout}> + {dataSet.name} + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"路径"} {...formItemLayout}> + {dataSet.url} + {dataSet.urlType == 1 && "(相对地址)"} + {dataSet.urlType == 0 && "(绝对地址)"} + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"描述"} {...formItemLayout}> + <TextArea value={dataSet.description} rows={5} disabled={true} /> + </FormItem> + </Col> + </Row> + <Row type="flex" gutter={20} style={{ width: '75%' }} justify="center"> + <Col> + <Button onClick={this.props.cancelData}>取消</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit">编辑</Button> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + } + </div> + ) + } +} + +// const SHOW_PARENT = TreeSelect.SHOW_PARENT; +const ModuleDetailEditForm = Form.create()(ModuleDetailEdit); +export default ModuleDetailEditForm; \ No newline at end of file diff --git a/src/module/huge-base/ModulesManage.jsx b/src/module/huge-base/ModulesManage.jsx new file mode 100644 index 0000000..64bc2c9 --- /dev/null +++ b/src/module/huge-base/ModulesManage.jsx @@ -0,0 +1,314 @@ +import React from 'react'; +import { Row, Col, Form, message, Modal, Popconfirm, Empty, Spin } from 'antd'; +import moment from 'moment'; +import SearchTree from '../../components/common/Tree'; +import fetch from '../../api/request'; +import ModuleDetailEdit from './ModuleDetailEdit'; + +const confirm = Modal.confirm; + +class ModulesManage extends React.Component { + constructor(props) { + super(props); + this.state = { + treeKey: Date.now(), + expandedKeys: [], + tableData: [], + totalElements: 1, + pageSize: 10, + treeData: [], + edit: 'false', + rightShow: false, + dataSet: {}, + currentNode: [], + moduleId: '', + saveParams: { + id: '', + parentId: '', + appId: '' + }, + selectedKeys: [], + treeLoading: false,//左侧树形数据loading + loading: false,//右侧详情loading + + }; + } + + componentDidMount() { + this.loadData() + } + + //加载左侧树形数据 + loadData = () => { + this.setState({ treeLoading: true }); + fetch({ + url: `api/module/getAllModulesByTree` + }).then(res => { + this.setState({ treeLoading: false }) + if (res) { + res = this.handleTreeData(res); + this.setState({ + treeData: res, + treeKey: Date.now() + }) + } + }) + }; + + //处理树形数据 + handleTreeData = data => { + for (let i = 0; i < data.length; i++) { + const node = data[i]; + node.key = node.id; + node.title = node.name; + if (data[i].modules) { + data[i].children = data[i].modules; + this.handleTreeData(node.children); + } + if (data[i].children) { + this.handleTreeData(node.children); + } + // else{ + // this.handleTreeData([node]) + // } + } + return data; + }; + + editFun = () => { + this.setState({ + edit: 'true' + }) + } + + //点击保存按钮 + saveFun = (data) => { + let { saveParams } = this.state; + console.log('data', this.state.saveParams) + this.setState({ + edit: 'false', + // dataSet: data, + loading: true + }); + fetch({ + url: `api/module/save`, + method: 'POST', + data: { ...data, ...saveParams } + }).then(res => { + this.setState({ loading: false }); + if (res) { + message.success("保存成功"); + this.setState({ dataSet: data }); + this.loadData(); + // 处于新增节点的场景,保存成功之后,隐藏详情,清空表单数据(执行清空操作) + if (!saveParams.id) { + this.clearKeys(); + } + } + }) + } + + //取消(保存界面下) + cancelFun = () => { + const { dataSet, currentNode } = this.state; + if (currentNode.length == 0) { + this.setState({ + rightShow: false + }) + } else { + this.setState({ + edit: 'false' + }); + if (Object.keys(dataSet).length == 0) { + // getModuleDetail(currentNode[0].id).then(res => { + // this.setState({ + // dataSet: res.data, + // loading: false + // }) + // }) + } + } + } + + //取消(查看界面下) + cancelData = () => { + this.setState({ + rightShow: false, + dataSet: {},//清空表单数据 + selectedKeys: [], + currentNode: [] + }) + } + + onSelect = (selectedKeys) => { + let _this = this; + _this.setState({ + selectedKeys + }) + } + + // 点击树形节点触发函数 + treeSelect = (tableData, currentNode) => { + // 此处做判断,如果是根节点(顶级),点击时不出现右边编辑 + if (currentNode[0].root) { + this.setState({ + rightShow: false, + currentNode, + saveParams: { + ...this.state.saveParams, + appId: currentNode[0].id + }, + selectedKeys: [currentNode[0].id] + }) + // message.error('请选择子节点模块'); + return + } + this.setState({ + rightShow: true + }) + // 此处为对应(模块、菜单)的详情 + this.setState({ + dataSet: {},//先清空之前的表单数据 + leafNodes: tableData, + currentNode, + saveParams: { + ...this.state.saveParams, + appId: currentNode[0].appId || currentNode[0].id, + id: currentNode[0].id, + } + }, () => { + this.setState({ loading: true }); + fetch({ + url: `api/module/getById`, + params: { id: currentNode[0].id } + }).then(res => { + this.setState({ loading: false }) + if (res) { + this.setState({ edit: 'false', dataSet: res }) + } + }) + + }) + }; + + //清除选中 + clearKeys = () => { + this.setState({ + dataSet: {}, + currentNode: [], + rightShow: false, + selectedKeys: [] + }) + } + + //点击左侧添加按钮,添加模块 + addBtn = () => { + const { currentNode } = this.state; + if (currentNode.length == 0 || currentNode[0].length == 0) { + message.error("请选择节点之后添加"); + return; + } + this.setState({ + rightShow: true, + dataSet: {}, + edit: 'true', + saveParams: { + ...this.state.saveParams, + id: '', + parentId: '' + } + }) + } + + //点击删除按钮 + deleteBtn = (node) => { + const { currentNode } = this.state; + if (node == "") { + message.error("没有选择资源,无法删除") + } else { + if (currentNode[0].root) { + message.error("请选择子模块进行删除") + } + else { + this.ConfirmTip(node) + } + } + } + + ConfirmTip = (node) => { + let _this = this; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该资源吗?</span>, + content: <span style={{ fontSize: 18 }}>删除该资源的同时,会删除与该资源的所有关系,也会删除所有的子资源。</span>, + onOk() { + fetch({ + url: `api/module/delete`, + params: { ids: node.id } + }).then(res => { + if (res) { + message.success('模块删除成功'); + _this.setState({ rightShow: false}); + _this.loadData(); + } + }) + }, + onCancel() { }, + }); + } + + onExpand = (expandedKeys) => { + this.setState({ + expandedKeys, + }); + } + + render() { + const { treeKey, rightShow, treeData, edit, treeLoading, loading } = this.state; + const saveParams = { + ...this.state.saveParams, + currentNode: this.state.currentNode, + } + + return ( + <div className="modulesmanage-main h-100 margin padding bg-white"> + <div className="padding h-100"> + <Row style={{ height: '100%' }} > + <Col span={8} style={{ border: "1px solid #e8e8e8", padding: 10 }} className="h-100"> + <Spin spinning={treeLoading}> + <SearchTree key={treeKey} + data={treeData} + onExpand={this.onExpand} + expandedKeys={this.state.expandedKeys} + treeSelect={this.treeSelect} + add={this.addBtn} + delete={this.deleteBtn} + clearKeys={this.clearKeys} + onSelect={this.onSelect} + selectedKeys={this.state.selectedKeys} + /> + </Spin> + </Col> + <Col span={1}></Col> + <Col span={15} style={{ border: "1px solid #e8e8e8" }} className="h-100"> + { + rightShow && + <ModuleDetailEdit loading={loading} edit={edit} editFun={this.editFun} saveFun={this.saveFun} cancelFun={this.cancelFun} dataSet={this.state.dataSet} params={saveParams} cancelData={this.cancelData}></ModuleDetailEdit> + } + { + !rightShow && + <Empty description={'暂无数据,请点击左侧树形结构'} className="h-100 flex-box-column align-center justify-content" /> + } + </Col> + </Row> + <Row> + </Row> + </div> + </div> + ) + } +} + + + +const ModulesManageList = Form.create()(ModulesManage); +export default ModulesManageList; \ No newline at end of file diff --git a/src/module/huge-base/RoleDetail.jsx b/src/module/huge-base/RoleDetail.jsx new file mode 100644 index 0000000..2e9753b --- /dev/null +++ b/src/module/huge-base/RoleDetail.jsx @@ -0,0 +1,187 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Form, Input, Button, message, Spin, TreeSelect } from 'antd'; +import MultiSelect from '../../components/common/multiSelect'; +import { createHashHistory } from 'history'; +import fetch from '../../api/request'; + +const history = createHashHistory(); +const { TextArea } = Input; +const FormItem = Form.Item; + +class RoleDetail extends React.Component { + constructor(props) { + super(props) + this.id = props.match.params.id == 'new' ? '' : props.match.params.id; + this.flag = props.match.params.flag == 'Modify' ? '修改' : '新增'; + + this.state = { + spinning: false,//页面loading + groupList: [], + ownGroups: [], + title: '修改', + dataSet: {}, + } + } + + componentDidMount() { + let p = [this.findGroups()]; + if (this.id) { + p = p.concat(this.getRoleDetail()) + } + this.setState({ spinning: true }); + Promise.all(p).then(res => { + console.log('res', res); + if (res.length == p.length) { + this.setState({ spinning: false }); + this.setState({ + groupList: res[0], //所有组 + }) + if (this.id) { + this.setState({ + dataSet: res[res.length - 1],//角色信息 + groupIds: res[res.length -1].groupIds || []//拥有组 + }) + } + } + }) + } + + //组 + findGroups = () => { + return new Promise((resolve, reject) => { + fetch({ + url: `api/group/finds`, + }).then(res => { + resolve(res) + }) + }) + } + + //角色详情 + getRoleDetail = () => { + return new Promise((resolve, reject) => { + fetch({ + url: `api/role/getById`, + params: { id: this.id } + }).then(res => { + resolve(res) + }) + }) + } + + groupChange = checkedValues => { + this.setState({ groupIds: checkedValues }) + } + + // 提交表单数据(新增 | 编辑) + handleSubmit = (e) => { + e.preventDefault(); + this.props.form.validateFields((err, values) => { + if (err) return; + this.setState({ spinning: true }); + fetch({ + url: `api/role/save`, + method: 'POST', + data: { + role: { ...values, id: this.id }, + groupIds: this.state.groupIds + } + }).then(res => { + this.setState({ spinning: false }); + if (res) { + message.success('保存角色成功'); + history.goBack(); + } + }) + }); + } + + //返回函数 + onBack = () => { + history.goBack(); + } + + render() { + const { getFieldDecorator } = this.props.form; + const formItemLayout1 = { + labelCol: { xs: { span: 24 }, sm: { span: 10 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 14 }, }, + }; + const formItemLayout2 = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + const { groupList, dataSet, groupIds } = this.state; + + return ( + <div className="roledetail-main h-100 margin padding bg-white"> + <Spin spinning={this.state.spinning}> + <div> + <Form onSubmit={this.handleSubmit}> + <Card title={'基础信息'} bordered={false} + extra={ + <Row type="flex" gutter={20}> + <Col> + <Button onClick={this.onBack}>返回</Button> + </Col> + <Col> + <Button htmlType="submit" type='primary'>确定</Button> + </Col> + </Row> + } + > + <Row type="flex"> + <Col span={8}> + <FormItem label={"标识符"} {...formItemLayout1}> + {getFieldDecorator('symbol', { + rules: [{ required: true, message: '标识符必填' }], + initialValue: dataSet.symbol || '' + })( + <Input placeholder="请输入标识符" /> + )}</FormItem> + </Col> + <Col span={8}> + <FormItem label={"角色名称"} {...formItemLayout1}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '角色名称必填' }], + initialValue: dataSet.name || '' + })( + <Input placeholder="请输入角色名称" /> + )}</FormItem> + </Col> + </Row> + <Row> + <Col span={16}> + <FormItem label={"描述"} {...formItemLayout2}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description || '' + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + </Card> + </Form> + <Card title={'拥有组'} bordered={false} extra={ + <Row> + <Link to={{ pathname: "/baseManage/group/Detail/new/Add", state: { id: '' } }}> + 没有组?点击新建 + </Link> + </Row> + }> + <Row> + <MultiSelect key={groupIds ? groupIds.toString() : 'init'} all={groupList} own={groupIds} onChange={this.groupChange} /> + </Row> + </Card> + </div> + </Spin> + </div> + ) + } +} + +const SHOW_PARENT = TreeSelect.SHOW_PARENT; +const RoleDetailForm = Form.create()(RoleDetail); +export default RoleDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/RoleManage.jsx b/src/module/huge-base/RoleManage.jsx new file mode 100644 index 0000000..c790f42 --- /dev/null +++ b/src/module/huge-base/RoleManage.jsx @@ -0,0 +1,114 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Row, Col, Button, message, Modal, Divider } from 'antd'; +import TableView from '../../components/common/TableView'; +import SearchFormView from '../../components/common/SearchFormView'; +import moment from 'moment'; +import fetch from '../../api/request'; + +const confirm = Modal.confirm; + +export default class RoleManage extends React.Component { + constructor(props) { + super(props); + this.state = { + formData: { + __key: Date.now(), + page: 1, + size: 10, + }, + + }; + } + + componentDidMount() { } + + setFormData = data => { + console.log('form', data); + this.setState({ + formData: data, + }); + } + + // 增加角色 + add = () => { + this.props.history.push('/organizationMgt/role/Detail/new/Add') + } + + //删除角色 + delete = (id) => { + let _this = this; + let { formData } = _this.state; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该角色吗?</span>, + content: <span style={{ fontSize: 18 }}>删除该角色的同时,会删除与该角色的所有关系。</span>, + onOk() { + fetch({ + url: `api/role/delete`, + params: { ids: id } + }).then(res => { + if (res) { + message.success("删除成功"); + _this.setState({ + formData: { + ...formData, + __key: Date.now()//刷新表格数据 + } + }) + } + }) + }, + onCancel() { }, + }); + } + + //表格列显示 + renderColumns = () => { + return [ + { title: '标识符', className: "txt-c", dataIndex: 'symbol' }, + { title: '角色名称', className: "txt-c", dataIndex: 'name' }, + { title: '描述', className: "txt-c", dataIndex: 'description', ellipsis: true, width: '35%' }, + { title: '创建时间', className: "txt-c", dataIndex: 'updateTime', render: (text, record) => text ? moment(text).format("YYYY-MM-DD HH:mm") : "" }, + { + title: '操作', className: "txt-c", key: 'operation', render: (text, record) => { + return <div> + <Link to={{ pathname: "/organizationMgt/role/Detail/" + record.id + '/Modify', query: { id: record.id } }}>修改</Link> + <Divider type="vertical" /> + <a onClick={() => this.delete(record.id)}>删除</a> + </div> + } + } + ] + } + + + + render() { + const { formData } = this.state; + let tableParams = { + url: `api/role/query`, + formData, + key: formData.__key, + columns: this.renderColumns(), + extraFromData: {}, + setFormData: this.setFormData + } + return ( + <div className="rolemanage-main h-100 margin padding bg-white"> + <SearchFormView + formData={formData} + setFormData={this.setFormData} + data={[ + { type: 'input', name: '标识符', label: '标识符', key: 'symbol' }, + { type: 'input', name: '角色名称', label: '角色名称', key: 'name' } + ]} /> + <Row type="flex" gutter={20} className="margin-bottom"> + <Col> + <Button type="primary" onClick={this.add}>新增角色</Button> + </Col> + </Row> + <TableView {...tableParams} /> + </div> + ) + } +} diff --git a/src/module/huge-base/UnitDetailEdit.jsx b/src/module/huge-base/UnitDetailEdit.jsx new file mode 100644 index 0000000..a42cc6e --- /dev/null +++ b/src/module/huge-base/UnitDetailEdit.jsx @@ -0,0 +1,167 @@ +/* eslint-disable */ +import React from 'react'; +import { Card, Row, Col, Form, Input, Button, Spin, message } from 'antd'; +import fetch from '../../api/request'; + +const { TextArea } = Input; +const FormItem = Form.Item; + +class GroupDetail extends React.Component { + constructor(props) { + super(props) + this.state = { + spinning: false, + id: '', + parentId: '', + dataSet: {}, + btnLoading: false,//保存按钮loading + } + } + + componentWillMount() { + } + componentDidMount() { + } + + handleSubmit = (e) => { // 提交表单数据 + e.preventDefault(); + let parentId = ''; + if (this.props.params.currentNode.length == 0) { + //没有选中节点 + parentId = ''; + } else { + // 判断是新增还是编辑 + if (this.props.params.id == '') { + parentId = this.props.params.currentNode[0].id //此为新增 + } else { + parentId = this.props.params.currentNode[0].parentId //此为编辑 + } + } + this.props.form.validateFields((err, values) => { + if (err) return; + this.setState({ btnLoading: true }); + fetch({ + url: `api/unit/save`, + method: 'POST', + data: { + ...values, + id: this.props.params.id, + parentId + } + }).then(res => { + this.setState({ btnLoading: false }) + if (res) { + message.success("保存成功"); + this.props.saveFun(values);//触发父级保存响应函数,刷新页面数据 + } + }) + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 5 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 19 }, }, + }; + + const { params } = this.props; + const dataSet = this.props.dataSet || {}; + const { btnLoading } = this.state; + + return ( + <div> + { + this.props.edit == 'true' ? + <div> + <Spin spinning={this.props.loading}> + <div> + <Form onSubmit={this.handleSubmit}> + <Card title={this.props.params.id ? '单位信息(编辑)' : '单位信息(新增)'} bordered={false}> + { + this.props.params.currentNode.length > 0 && Object.keys(dataSet).length == 0 && + <Row type="flex"> + <Col span={16}> + <FormItem label={"上级单位"} {...formItemLayout}> + <span>{params.currentNode[0].name}</span> + </FormItem> + </Col> + </Row> + } + <Row type="flex"> + <Col span={16}> + <FormItem label={"单位名称"} {...formItemLayout}> + {getFieldDecorator('name', { + rules: [{ required: true, message: '请输入单位名称' }], + initialValue: dataSet.name || '', + })( + <Input placeholder="请输入单位名称" /> + )}</FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"描述"} {...formItemLayout}> + {getFieldDecorator('description', { + rules: [{ max: 200, message: '描述的内容不能超过200字' }], + initialValue: dataSet.description || '' + })( + <TextArea placeholder="请输入描述" rows={5} /> + )}</FormItem> + </Col> + </Row> + <Row type="flex" justify="center" gutter={20} style={{ width: '75%' }}> + <Col> + <Button onClick={this.props.cancelFun}>取消</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit" loading={btnLoading}>保存</Button> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + : + <div> + <Spin spinning={this.props.loading}> + <div> + <Form onSubmit={this.props.editFun}> + + <Card title={'单位信息'} bordered={false}> + <Row type="flex"> + <Col span={16}> + <FormItem label={"单位名称"} {...formItemLayout} style={{ marginBottom: 10 }}> + <span>{dataSet.name || '暂无'}</span> + </FormItem> + </Col> + </Row> + <Row type="flex"> + <Col span={16}> + <FormItem label={"描述"} {...formItemLayout} style={{ marginBottom: 10 }}> + {dataSet.description || '暂无'} + </FormItem> + </Col> + </Row> + <Row type='flex' gutter={20} justify="center" style={{ width: '75%' }}> + <Col> + <Button onClick={this.props.cancelData}>取消</Button> + </Col> + <Col> + <Button className="button-do" htmlType="submit" type="primary">编辑</Button> + </Col> + </Row> + </Card> + </Form> + </div> + </Spin> + </div> + } + </div> + ) + } +} + +const GroupDetailForm = Form.create()(GroupDetail); +export default GroupDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/UnitManage.jsx b/src/module/huge-base/UnitManage.jsx new file mode 100644 index 0000000..999c139 --- /dev/null +++ b/src/module/huge-base/UnitManage.jsx @@ -0,0 +1,252 @@ +import React from 'react'; +import { Row, Col, Form, message, Modal, Empty, Spin } from 'antd'; +import SearchTree from '../../components/common/Tree'; +import fetch from '../../api/request'; +import UnitDetailEdit from './UnitDetailEdit'; + +const confirm = Modal.confirm; + +class UnitManage extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: false,//右侧详情loading + resourceList: [], + treeKey: 'init', + expandedKeys: [], + tableData: [], + totalElements: 1, + pageSize: 10, + treeData: [], + edit: 'false', + rightShow: false, + dataSet: {}, + currentNode: [], + id: '', + selectedKeys: [] + }; + } + + componentDidMount() { + this.loadData() + } + + // 加载单位树形数据 + loadData = () => { + this.setState({ + treeLoading: true + }) + fetch({ + url: `api/unit/getAllUnitsByCascade` + }).then(res => { + res = this.handleTreeData(res); + if (res) { + this.setState({ + treeLoading: false, + treeData: res,//树形数据 + treeKey: Date.now() + }) + } + }) + }; + + //处理树形数据 + handleTreeData = data => { + for (let i = 0; i < data.length; i++) { + const node = data[i]; + node.key = node.id; + node.title = node.name; + if (data[i].children) { + this.handleTreeData(node.children); + } + } + return data; + }; + + editFun = () => { + this.setState({ + edit: 'true' + }) + } + + saveFun = (obj) => { + this.setState({ + edit: 'false', + dataSet: obj, + expandedKeys: [] + }) + this.loadData(); + this.setState({ treeKey: Date.now() }) + } + + cancelFun = () => { + const { dataSet, currentNode } = this.state; + if (currentNode.length == 0) { + this.setState({ + rightShow: false + }) + } else { + this.setState({ + edit: 'false' + }); + if (Object.keys(dataSet).length == 0) { + // Fetch.unitDetail({id: currentNode[0].id}).then(res => { + // _this.setState({ + // dataSet: res, + // id: currentNode[0].id, + // loading: false + // }) + // }) + } + } + + } + + cancelData = () => { + let _this = this; + this.setState({ + rightShow: false, + selectedKeys: [], + currentNode: [] + }); + } + + onSelect = (selectedKeys) => { + let _this = this; + _this.setState({ + selectedKeys + }) + } + + // 点击任意节点都可以查看、编辑、添加(获取单位信息详情) + treeSelect = (tableData, currentNode) => { + this.setState({ + rightShow: true, + loading: true, + leafNodes: tableData, + currentNode, + selectedKeys: [currentNode[0].id] + }, () => { + fetch({ + url: `api/unit/getById`, + params: { id: currentNode[0].id } + }).then(res => { + if (res) { + this.setState({ + edit: 'false', + dataSet: res, + id: currentNode[0].id, + loading: false + }) + } + }) + }) + }; + + addBtn = () => { + this.setState({ + rightShow: true, + dataSet: {}, + edit: 'true', + id: '' + }) + } + + //删除按钮 + deleteBtn = (node) => { + if (node == "") { + message.error("没有选择资源,无法删除") + } else { + this.ConfirmTip(node); + } + } + + //删除单位(提示操作) + ConfirmTip = (node) => { + let _this = this; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该资源吗?</span>, + content: <span style={{ fontSize: 18 }}>删除该资源的同时,会删除与该资源的所有关系,也会删除所有的子资源。</span>, + onOk() { + fetch({ + url: `api/unit/delete`, + params: { + ids: node.id + } + }).then(res => { + if (res) { + message.success('节点删除成功'); + _this.loadData(); + _this.setState({ treeKey: Date.now(), rightShow: false }) + } + }) + }, + onCancel() { }, + }); + } + + onExpand = (expandedKeys) => { + this.setState({ + expandedKeys + }); + } + + clearKeys = () => { + let _this = this; + _this.setState({ + currentNode: [], + rightShow: false + }) + } + + render() { + const { treeKey, rightShow, treeData, edit, treeLoading } = this.state; + + const params = { + currentNode: this.state.currentNode, + id: this.state.id + } + + return ( + <div className="unitmanage-main margin padding bg-white h-100"> + + <div className="h-100 padding"> + <Row style={{ height: '100%' }}> + <Col span={8} style={{ border: "1px solid #e8e8e8", padding: 10 }} className="h-100"> + <Spin spinning={treeLoading}> + <SearchTree key={treeKey} + data={treeData} + onExpand={this.onExpand} + expandedKeys={this.state.expandedKeys} + treeSelect={this.treeSelect} + add={this.addBtn} + delete={this.deleteBtn} + clearKeys={this.clearKeys} + onSelect={this.onSelect} + selectedKeys={this.state.selectedKeys} + /> + </Spin> + </Col> + <Col span={1}></Col> + <Col span={15} style={{ border: "1px solid #e8e8e8" }} className="h-100"> + { + rightShow && + <UnitDetailEdit edit={edit} editFun={this.editFun} saveFun={this.saveFun} cancelFun={this.cancelFun} dataSet={this.state.dataSet} params={params} cancelData={this.cancelData} loading={this.state.loading}></UnitDetailEdit>} + { + !rightShow && + <Empty description={'暂无数据,请点击左侧树形结构进行创建'} className="h-100 flex-box-column align-center justify-content" /> + } + </Col> + </Row> + <Row> + </Row> + </div> + </div> + ) + } + +} + + +const UnitManageList = Form.create()(UnitManage); +export default UnitManageList; \ No newline at end of file diff --git a/src/module/huge-base/UserDetail.jsx b/src/module/huge-base/UserDetail.jsx new file mode 100644 index 0000000..0f5a42f --- /dev/null +++ b/src/module/huge-base/UserDetail.jsx @@ -0,0 +1,444 @@ +/* eslint-disable */ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Card, Row, Col, Icon, Form, Input, Button, Select, Table, DatePicker, message, Breadcrumb, Spin, Layout, Upload, Modal } from 'antd'; +import MultiSelect from '../../components/common/multiSelect'; +import { BASE_URL } from '../../api/httpurl'; +import fetch from '../../api/request'; +import ChangePswView from '../../components/common/ChangePswView'; +import { createHashHistory } from 'history'; + +const history = createHashHistory(); +const FormItem = Form.Item; +const Option = Select.Option; + +class UserDetail extends React.Component { + constructor(props) { + super(props) + this.id = props.match.params.id == 'new' ? '' : props.match.params.id; + this.flag = props.match.params.flag == 'Modify' ? '修改' : '新增'; + this.state = { + spinning: false, + user: {}, + account: {}, + groupIds: [], //组 + roleIds: [], //角色 + + previewVisible: false, + previewImage: '', + fileList: [], + + roleList: [], + ownRoles: [], + groupList: [], + ownGroups: [], + changePswVisible: false, + btnLoading: false + } + } + componentDidMount() { + let p = [this.findGroups(), this.findRoles()]; + if (this.id) { + p = p.concat(this.getUserDetail()); + } + this.setState({ + spinning: true + }) + Promise.all(p).then(res => { + if (res.length == p.length) { + this.setState({ + spinning: false, + groupList: res[0], + roleList: res[1] + }); + if (this.id) { + let detail = res[res.length - 1]; //用户信息 + this.setState({ + dataSet: detail, + spinning: false, + user: detail.user, + account: detail.account, + groupIds: detail.groupIds, + roleIds: detail.roleIds, + fileList: (detail.user.avatar == null || detail.user.avatar == '') ? [] : [{ + uid: '-1', + name: 'xxx.png', + status: 'done', + url: detail.user.avatar + }] + }) + } + } + }) + } + + //组 + findGroups = () => { + return new Promise((resolve, reject) => { + fetch({ + url: `api/group/finds`, + }).then(res => { + resolve(res) + }) + }) + } + + // 角色 + findRoles = () => { + return new Promise((resolve, reject) => { + fetch({ + url: `api/role/finds`, + }).then(res => { + resolve(res) + }) + }) + } + + // 基础信息 + getUserDetail = () => { + return new Promise((resolve, reject) => { + fetch({ + url: `api/user/getById`, + params: { + id: this.id + } + }).then(res => { + if (res) { + resolve(res) + } + }) + }) + } + + // 返回函数 + goBack = () => { + history.goBack(); + } + + handleCancel = () => this.setState({ previewVisible: false }) + + handlePreview = (file) => { + this.setState({ + previewImage: file.url || file.thumbUrl, + previewVisible: true, + }); + } + + handleChange = ({ fileList, file }) => { + const { user } = this.state; + this.setState({ + fileList, + }) + if (file.status == 'done') { + this.setState({ + user: { + ...user, + avatar: file.response.data + } + }) + } + } + + handleRemove = ({ fileList }) => { + const { user } = this.state; + this.setState({ + user: { + ...user, + avatar: '' + }, + fileList: [] + }) + } + + roleChange = checkedValues => { + this.setState({ roleIds: checkedValues }) + } + groupChange = checkedValues => { + this.setState({ groupIds: checkedValues }) + } + + //修改用户密码 + onOK = (data) => { + let formData = { + accountId: this.state.account.id, + newPassword: data.newPassWord + } + this.setState({ + btnLoading: true + }) + fetch({ + url: `api/account/changePassword`, + params: formData + }).then(res => { + this.setState({ + btnLoading: false, + changePswVisible: false + }) + if (res) { + message.success("密码修改成功"); + } + }) + } + + // 确定修改|保存 + handleSubmit = (e) => { // 提交表单数据 + e.preventDefault(); + let _this = this; + _this.props.form.validateFields((err, values) => { + if (err) return; + _this.setState({ spinning: true }); + fetch({ + url: `api/user/save`, + method: 'POST', + data: { + account: { + ..._this.state.account, + id: _this.state.account.id || '', + account: values.account, + credential: values.credential, + }, + user: { + ..._this.state.user, + id: _this.state.user.id, + trueName: values.trueName, + sex: values.sex, + idcard: values.idcard, + mobile: values.mobile, + email: values.email, + }, + roleIds: _this.state.roleIds, + groupIds: _this.state.groupIds + } + }).then(res => { + _this.setState({ spinning: false }) + if (res) { + message.success('保存用户成功'); + history.goBack(); + } + }) + }) + } + + isMobile = (rule, value, callback) => { + const regMobile = /^0?1[3|4|5|8][0-9]\d{8}$/ + if (!regMobile.test(value)) { + if (value == "") { + callback(); + return; + } else { + callback('手机号码格式不正确'); + return; + } + } + callback() + } + + isIdCard = (rule, value, callback) => { + const regMobile = /^[1-9]\d{7}((0[1-9])|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/; + if (!regMobile.test(value)) { + if (value == "") { + callback(); + return; + } else { + callback('身份证号码格式不正确'); + return; + } + } + callback() + } + + render() { + const { getFieldDecorator } = this.props.form; + const formItemLayout = { + labelCol: { xs: { span: 24 }, sm: { span: 10 }, }, + wrapperCol: { xs: { span: 24 }, sm: { span: 14 }, }, + }; + const { user, account, groupIds, roleIds, previewVisible, previewImage, fileList, roleList, groupList, changePswVisible, btnLoading } = this.state; + const uploadButton = ( + <div> + <Icon type="plus" /> + <div className="ant-upload-text">上传头像</div> + </div> + ); + return ( + <div className="userdetail-main margin padding bg-white"> + + <Spin spinning={this.state.spinning}> + <Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}> + <img alt="example" style={{ width: '100%' }} src={previewImage} /> + </Modal> + <div style={{ margin: 20 }}> + <Form onSubmit={this.handleSubmit}> + <Card title="账号信息" bordered={false} extra={ + <Row type="flex" gutter={20}> + <Col> + <Button onClick={this.goBack}>返回</Button> + </Col> + <Col> + <Button type="primary" htmlType="submit" >确认</Button> + </Col> + </Row> + }> + <Row> + <Col span={16}> + { + this.flag == '修改' ? + <Row> + <Col span={12}> + <FormItem label={"账号"} {...formItemLayout}> + {account.account || ''} + </FormItem> + </Col> + <Col span={12}> + <FormItem label={"密码"} {...formItemLayout}> + {'********'} + </FormItem> + </Col> + </Row> + : + <Row> + <Col span={12}> + <FormItem label={"账号"} {...formItemLayout}> + {getFieldDecorator('account', { + rules: [{ required: true, message: '账号必填' }], + initialValue: account.account || '' + })( + <Input placeholder="请输入账号" /> + )}</FormItem> + </Col> + <Col span={12}> + <FormItem label={"密码"} {...formItemLayout} hasFeedback> + {getFieldDecorator('credential', { + rules: [{ required: true, message: '密码必填' }], + initialValue: account.credential || '' + })( + <Input.Password placeholder="请输入密码" type="password" /> + )}</FormItem> + </Col> + </Row> + } + </Col> + { + this.flag == '修改' && + <Col span={8}> + <div style={{ marginLeft: '20%' }}> + <Button type="primary" onClick={() => { + this.setState({ + changePswVisible: true + }) + }}>修改密码</Button> + </div> + </Col> + } + </Row> + </Card> + + <Card title="基础信息" bordered={false} > + <Row> + <Col span={16}> + <Row> + <Col span={12}> + <FormItem label={"姓名"} {...formItemLayout}> + {getFieldDecorator('trueName', { + rules: [{ required: true, message: '姓名必填' }], + initialValue: user.trueName || '' + })( + <Input placeholder="请输入姓名" /> + )}</FormItem> + </Col> + <Col span={12}> + <FormItem label={"性别"} {...formItemLayout}> + {getFieldDecorator('sex', { + rules: [{ required: true, message: '微信用户名称必填' }], + initialValue: user.sex || undefined + })( + <Select placeholder="请选择"> + <Option value={1}>男</Option> + <Option value={2}>女</Option> + </Select> + )}</FormItem> + </Col> + </Row> + <Row> + <Col span={12}> + <FormItem label={"手机号码"} {...formItemLayout}> + {getFieldDecorator('mobile', { + rules: [{ + required: true, message: '手机号码必填' + }, { + validator: this.isMobile + }], + initialValue: user.mobile || '' + })( + <Input placeholder="请输入手机号码" /> + )}</FormItem> + </Col> + <Col span={12}> + <FormItem label={"电子邮箱"} {...formItemLayout}> + {getFieldDecorator('email', { + rules: [{ + type: 'email', message: '电子邮箱格式不正确', + }], + initialValue: user.email || '' + })( + <Input placeholder="请输入电子邮箱" /> + )}</FormItem> + </Col> + </Row> + <Row> + <Col span={12}> + <FormItem label={"身份证号码"} {...formItemLayout}> + {getFieldDecorator('idcard', { + rules: [{ + required: true, message: '身份证号码必填' + }, { + validator: this.isIdCard + }], + initialValue: user.idcard || '' + })( + <Input placeholder="请输入身份证号码" /> + )}</FormItem> + </Col> + </Row> + </Col> + <Col span={8}> + <div style={{ marginLeft: '20%' }}> + <Upload + action={BASE_URL + `api/user/uploadAvatar`} + listType="picture-card" + fileList={fileList} + onPreview={this.handlePreview} + onChange={this.handleChange} + onRemove={this.handleRemove} + > + {fileList.length > 0 ? null : uploadButton} + </Upload> + </div> + </Col> + </Row> + </Card> + </Form> + + <Card title="拥有角色" bordered={false} extra={<Link to={{ pathname: "/organizationMgt/roleDetail/new/Add", state: { id: 'new' } }}>没有角色?点击新建</Link>}> + <Row> + <MultiSelect key={roleIds ? roleIds.toString() : 'init'} all={roleList} own={roleIds} onChange={this.roleChange} /> + </Row> + </Card> + + <Card title="拥有组" bordered={false} extra={<Link to={{ pathname: "/baseManage/groupDetail/new/Add", state: { id: '' } }}>没有组?点击新建</Link>}> + <Row> + <MultiSelect key={groupIds ? groupIds.toString() : 'init'} all={groupList} own={groupIds} onChange={this.groupChange} /> + </Row> + </Card> + </div> + </Spin> + { + changePswVisible && <ChangePswView onCancel={() => { this.setState({ changePswVisible: false }) }} onOK={this.onOK} btnLoading={btnLoading} /> + } + </div> + ) + } +} + +const UserDetailForm = Form.create()(UserDetail); +export default UserDetailForm; \ No newline at end of file diff --git a/src/module/huge-base/UserManage.jsx b/src/module/huge-base/UserManage.jsx new file mode 100644 index 0000000..5f6ea8a --- /dev/null +++ b/src/module/huge-base/UserManage.jsx @@ -0,0 +1,139 @@ +/* eslint-disable */ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Row, Col, Icon, Button, Select, message, Modal, Divider, Avatar } from 'antd'; +import TableView from '../../components/common/TableView'; +import SearchFormView from '../../components/common/SearchFormView'; +import moment from 'moment'; +import fetch from '../../api/request'; + +const confirm = Modal.confirm; + +export default class UserManage extends React.Component { + constructor(props) { + super(props); + this.state = { + formData: { + __key: Date.now(), + page: 1, + size: 10, + }, + userSyncLoading: false + }; + } + + componentDidMount() { } + + setFormData = data => { + this.setState({ + formData: data, + }); + } + + // 新增用户 + add = () => { + this.props.history.push('/baseManage/user/Detail/new/Add') + } + + // 微信同步 + userSync = () => { + this.setState({ userSyncLoading: true }) + fetch({ + url: `api/user/syncCpUser` + }).then(res => { + this.setState({ userSyncLoading: false }); + if (res) { + message.success("同步成功!"); + this.setState({ + formData: { + ...this.state.formData, + __key: Date.now() + } + }) + } + }) + } + + //表格列显示 + renderColumns = () => { + return [ + { title: '头像', className: "txt-c", dataIndex: 'avatar', key: 'avatar', render: (text, record) => text ? <image style={{ height: 23, width: 25 }} src={text} /> : <Avatar icon="user" /> }, + { title: '姓名', className: "txt-c", dataIndex: 'trueName', key: 'trueName' }, + { title: '身份证', className: "txt-c", dataIndex: 'idcard', key: 'idcard' }, + { title: '邮箱', className: "txt-c", dataIndex: 'email', key: 'email' }, + { title: '手机号码', className: "txt-c", dataIndex: 'mobile', key: 'mobile' }, + { title: '创建时间', className: "txt-c", dataIndex: 'createTime', key: 'createTime', render: (text, record) => text !== "" && text != null ? moment(text).format("YYYY-MM-DD HH:mm") : "" }, + { + title: '操作', className: "txt-c", key: 'operation', render: (text, record) => { + return <div> + <Link to={{ pathname: "/baseManage/user/Detail/" + record.id + '/Modify', query: { id: record.id } }}>修改</Link> + <Divider type="vertical" /> + <a onClick={() => this.delete(record.id)}>删除</a> + </div> + } + } + ] + } + + //删除用户 + delete = (id) => { + let _this = this; + confirm({ + title: <span style={{ fontSize: 19 }}>确定要删除该用户吗?</span>, + onOk() { + fetch({ + url: 'api/user/delete', + params: { + ids: id + } + }).then(res => { + if (res) { + message.success("删除成功"); + _this.setState({ + formData: { + ..._this.state.formData, + __key: Date.now() + } + }) + } + }) + }, + onCancel() { }, + }); + } + + render() { + const { formData, userSyncLoading } = this.state; + let tableParams = { + url: `api/user/query`, + formData, + key: formData.__key, + columns: this.renderColumns(), + extraFromData: {}, + setFormData: this.setFormData + } + + return ( + <div className="usermanage-main margin padding bg-white"> + <SearchFormView + formData={formData} + setFormData={this.setFormData} + data={[ + { type: 'input', name: '姓名', label: '姓名', key: 'trueName' }, + { type: 'input', name: '身份证号码', label: '身份证号码', key: 'idcard' }, + { type: 'input', name: '手机号码', label: '手机号码', key: 'mobile' }, + { type: 'input', name: '电子邮箱', label: '电子邮箱', key: 'email' }, + ]} /> + <Row type="flex" gutter={20} className="margin-bottom"> + <Col> + <Button type="primary" loading={userSyncLoading} onClick={this.userSync}>同步微信用户</Button> + </Col> + <Col> + <Button type="primary" onClick={this.add}>新增用户</Button> + </Col> + </Row> + <TableView {...tableParams} /> + </div> + ) + } +} diff --git a/src/pages/login/login.jsx b/src/module/login/login.jsx similarity index 84% rename from src/pages/login/login.jsx rename to src/module/login/login.jsx index 3d77cf0..30856a9 100644 --- a/src/pages/login/login.jsx +++ b/src/module/login/login.jsx @@ -10,8 +10,8 @@ import './login.scss'; import logo from '../../img/logo.png'; - import fetch from '../../api/request'; +import { oaMenus, userMenus, getMenuListByPermission } from '../../menu'; class NormalLoginForm extends React.Component { constructor(props) { @@ -66,8 +66,22 @@ console.log('res', res); if (res) { window.localStorage.setItem('menu', JSON.stringify(res)); + window.localStorage.setItem('menusListByRole', JSON.stringify({ + user: { role: 'user', menus: userMenus }, + oa: { + role: 'oa', menus: getMenuListByPermission(oaMenus, res && res.map(({ symbol }) => (symbol)).concat(res.map(({ moduleSymbol }) => (moduleSymbol))).reduce((p, n) => { + if (p.indexOf(n) == -1) { + return p.concat(n) + } else { + return p + } + }, [])) + } + }));//所有模块菜单 message.success('登录成功'); - this.props.history.push({ pathname: "/index" }); + setTimeout(() => { + this.props.history.push({ pathname: "/index" }); + }, 1500);//延时跳转 } }) } @@ -99,7 +113,7 @@ <Form.Item className="login-div-content-form-flex"> {getFieldDecorator('credential', { rules: [{ required: true, message: '请输入密码!' }], - initialValue: 'admin' + // initialValue: 'admin' })( <Input style={{ width: '300px', height: '48px', margin: '12px' }} diff --git a/src/pages/login/login.scss b/src/module/login/login.scss similarity index 100% rename from src/pages/login/login.scss rename to src/module/login/login.scss diff --git a/src/module/menu/menu.jsx b/src/module/menu/menu.jsx new file mode 100644 index 0000000..8f486c1 --- /dev/null +++ b/src/module/menu/menu.jsx @@ -0,0 +1,81 @@ +/* eslint-disable */ +/**柯礼钦 + * 4/2/2020, 11:22:51 AM + * doc comment for the file goes here + */ + +/** 菜单组件 */ + +import React from 'react'; +import { Spin, Layout, Menu, Icon } from 'antd'; +import MenView from '../../components/common/MenuView'; +import { oaMenus, getMenuListByPermission } from '../../menu'; +import fetch from '../../api/request'; +import { Context } from '../../index'; + +const { Sider } = Layout; + +function find(data, pathname) { + for (const { path, children } of data) { + if (path === pathname) return path; + if (children) { + const result = find(children, pathname); + if (result) return result; + } + } + return null; +} + +function selected(data, pathname) { + if (!pathname || pathname === '/') return pathname; + return find(data, pathname) || selected(data, pathname.split('/').slice(0, -1).join('/')); +} + +export default class MenuView extends React.Component { + // static contextType = context; + constructor(props) { + super(props); + this.state = { + collapsed: true, + menusListByRole: null + }; + } + + componentDidMount() { + // 获取从登录页面记录在缓存里的菜单数据 + let menusListByRole = window.localStorage.getItem('menusListByRole') ? JSON.parse(window.localStorage.getItem('menusListByRole')) : null; + this.setState({ menusListByRole }); + } + + onCollapse = collapsed => { + this.setState({ collapsed }); + } + + render() { + const { collapsed, menusListByRole } = this.state; + return ( + <Context.Consumer> + {({ role }) => ( + <React.Fragment> + <Sider + onCollapse={this.onCollapse} + collapsed={collapsed} + breakpoint="lg" + collapsible={true} + > + { + menusListByRole && + <MenView + history={this.props.history} + pathname={selected(menusListByRole[role].menus, this.props.location.pathname)} + menudata={menusListByRole[role].menus || []} + /> + } + </Sider> + </React.Fragment> + )} + </Context.Consumer> + ); + } + +} diff --git a/src/pages/document/DocumentDetail.jsx b/src/module/oa/document/DocumentDetail.jsx similarity index 84% rename from src/pages/document/DocumentDetail.jsx rename to src/module/oa/document/DocumentDetail.jsx index df40271..61e4a38 100644 --- a/src/pages/document/DocumentDetail.jsx +++ b/src/module/oa/document/DocumentDetail.jsx @@ -8,8 +8,8 @@ import React, { ReactNode, ReactEventHandler, Component } from 'react'; // import { Link } from 'react-router-dom'; // import { Icon } from 'antd'; -import BreadcrumbView from '../../components/common/BreadcrumbView'; -import DocumentDetailPage from '../../components/page/DocumentDetailPage'; +import BreadcrumbView from '../../../components/common/BreadcrumbView'; +import DocumentDetailPage from '../../../components/oa/DocumentDetailPage'; export default class DocumentDetail extends Component { constructor(props) { diff --git a/src/pages/document/DocumentEdit.jsx b/src/module/oa/document/DocumentEdit.jsx similarity index 85% rename from src/pages/document/DocumentEdit.jsx rename to src/module/oa/document/DocumentEdit.jsx index e0f05bf..71e9e88 100644 --- a/src/pages/document/DocumentEdit.jsx +++ b/src/module/oa/document/DocumentEdit.jsx @@ -8,8 +8,8 @@ import React, { ReactNode, ReactEventHandler, Component } from 'react'; // import { Link } from 'react-router-dom'; // import { Icon } from 'antd'; -import BreadcrumbView from '../../components/common/BreadcrumbView'; -import DocumentEditPage from '../../components/page/DocumentEditPage' +import BreadcrumbView from '../../../components/common/BreadcrumbView'; +import DocumentEditPage from '../../../components/oa/DocumentEditPage' export default class DocumentEdit extends Component { constructor(props) { diff --git a/src/pages/index/Announcement.jsx b/src/module/oa/index/Announcement.jsx similarity index 79% rename from src/pages/index/Announcement.jsx rename to src/module/oa/index/Announcement.jsx index 0462c88..6b2035c 100644 --- a/src/pages/index/Announcement.jsx +++ b/src/module/oa/index/Announcement.jsx @@ -6,8 +6,8 @@ /** Happy Coding */ import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import BreadcrumbView from '../../components/common/BreadcrumbView'; -import AnnouncementPage from '../../components/page/AnnouncementPage' +import BreadcrumbView from '../../../components/common/BreadcrumbView'; +import AnnouncementPage from '../../../components/oa/AnnouncementPage' export default class Announcement extends Component { constructor(props) { diff --git a/src/pages/index/System.jsx b/src/module/oa/index/System.jsx similarity index 79% rename from src/pages/index/System.jsx rename to src/module/oa/index/System.jsx index 0dcf598..4e0b0e0 100644 --- a/src/pages/index/System.jsx +++ b/src/module/oa/index/System.jsx @@ -6,8 +6,8 @@ /** Happy Coding */ import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import BreadcrumbView from '../../components/common/BreadcrumbView'; -import RulesList from '../../components/page/index/rulesList' +import BreadcrumbView from '../../../components/common/BreadcrumbView'; +import RulesList from '../../../components/oa/index/rulesList' export default class System extends Component { constructor(props) { diff --git a/src/module/oa/index/workbench.jsx b/src/module/oa/index/workbench.jsx new file mode 100644 index 0000000..0132823 --- /dev/null +++ b/src/module/oa/index/workbench.jsx @@ -0,0 +1,61 @@ +/* eslint-disable */ +/**柯礼钦 + * 4/6/2020, 10:16:55 AM + * doc comment for the file goes here + */ + +/** 首页 -- 工作台 */ +import React, { ReactNode, ReactEventHandler, Component } from 'react'; +import BreadcrumbView from '../../../components/common/BreadcrumbView'; +import WorkbenchPage from '../../../components/oa/index/workbench' + +export default class Workbench extends Component { + constructor(props) { + super(props); + this.config = { + }; + this.state = { + }; + } + + componentWillMount() { } + + componentDidMount() { + // let _this = this; + + // this.iframeWin = this.refs.iframe.contentWindow; + // this.refs.iframe && this.refs.iframe.addEventListener("load", function () { + // //代码能执行到这里说明已经载入成功完毕了 + // console.log('执行完'); + // //这里是回调函数 + // _this.iframeWin.postMessage({ + // token: window.localStorage.getItem('token') || undefined + // }, '*'); + // }, false); + } + + componentDidShow() { } + + render() { + return ( + <div className="workbench-page-main flex-box-column"> + <div className="flex-1"> + <WorkbenchPage {...this.props} /> + {/* <iframe + className="h-100" + style={{ width: '100%' }} + onLoad={() => { }} + ref="iframe" + src={'http://localhost:3000/#/index'} + width="100%" + height={this.state.iFrameHeight} + scrolling="no" + frameBorder="0" + /> */} + + </div> + </div> + ) + } +} + diff --git a/src/pages/logManage/Rawler.jsx b/src/module/oa/logManage/Rawler.jsx similarity index 88% rename from src/pages/logManage/Rawler.jsx rename to src/module/oa/logManage/Rawler.jsx index 4f26819..d85f9a3 100644 --- a/src/pages/logManage/Rawler.jsx +++ b/src/module/oa/logManage/Rawler.jsx @@ -6,7 +6,7 @@ /** 爬虫词条管理 */ import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import RawlerPage from '../../components/page/logManage/Rawler' +import RawlerPage from '../../../components/oa/logManage/Rawler' export default class Rawler extends Component { diff --git a/src/pages/logManage/browseLog.jsx b/src/module/oa/logManage/browseLog.jsx similarity index 88% rename from src/pages/logManage/browseLog.jsx rename to src/module/oa/logManage/browseLog.jsx index 1c8c204..c2f375d 100644 --- a/src/pages/logManage/browseLog.jsx +++ b/src/module/oa/logManage/browseLog.jsx @@ -6,7 +6,7 @@ /** 浏览日志 */ import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import BrowseLogPage from '../../components/page/logManage/browseLog'; +import BrowseLogPage from '../../../components/oa/logManage/browseLog'; export default class BrowseLog extends Component { constructor(props) { diff --git a/src/pages/logManage/operLog.jsx b/src/module/oa/logManage/operLog.jsx similarity index 88% rename from src/pages/logManage/operLog.jsx rename to src/module/oa/logManage/operLog.jsx index 7f2d1e9..e2c6aab 100644 --- a/src/pages/logManage/operLog.jsx +++ b/src/module/oa/logManage/operLog.jsx @@ -6,7 +6,7 @@ /** 操作日志 */ import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import OperLogPage from '../../components/page/logManage/operLog' +import OperLogPage from '../../../components/oa/logManage/operLog' export default class OperLog extends Component { constructor(props) { diff --git a/src/pages/personal/information.jsx b/src/module/oa/personal/information.jsx similarity index 90% rename from src/pages/personal/information.jsx rename to src/module/oa/personal/information.jsx index 362e006..4ce97b2 100644 --- a/src/pages/personal/information.jsx +++ b/src/module/oa/personal/information.jsx @@ -6,7 +6,7 @@ /** 个人信息 */ import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import InformationPage from '../../components/page/personal/information'; +import InformationPage from '../../../components/oa/personal/information'; import { now } from 'moment'; export default class Information extends Component { diff --git a/src/pages/Index.jsx b/src/pages/Index.jsx deleted file mode 100644 index 9cbd063..0000000 --- a/src/pages/Index.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * 姓名<example@email.com> - * 2019年12月10日 17:17 - * - */ - - -import React from 'react'; -// import { Modal } from 'antd-mobile'; -// import { Icon } from 'antd'; -import fetch from '../api/request'; - -export default class Index extends React.Component { - constructor(props) { - super(props); - this.state = { - data: null - }; - } - - componentDidMount() { - document.title = 'Index'; - } - - render() { - return ( - <div className="app-page"> - Index页面 - </div> - ); - } - -} diff --git a/src/pages/index/workbench.jsx b/src/pages/index/workbench.jsx deleted file mode 100644 index aa2fa7d..0000000 --- a/src/pages/index/workbench.jsx +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable */ -/**柯礼钦 - * 4/6/2020, 10:16:55 AM - * doc comment for the file goes here - */ - -/** 首页 -- 工作台 */ -import React, { ReactNode, ReactEventHandler, Component } from 'react'; -import BreadcrumbView from '../../components/common/BreadcrumbView'; -import WorkbenchPage from '../../components/page/index/workbench' - -export default class Workbench extends Component { - constructor(props) { - super(props); - this.config = { - }; - this.state = { - }; - } - - componentWillMount() { } - - componentDidMount() { } - - componentDidShow() { } - - render() { - return ( - <div className="workbench-page-main flex-box-column"> - <div className="flex-1"> - <WorkbenchPage {...this.props}/> - </div> - </div> - ) - } -} - diff --git a/src/pages/menu/menu.jsx b/src/pages/menu/menu.jsx deleted file mode 100644 index 54f24d3..0000000 --- a/src/pages/menu/menu.jsx +++ /dev/null @@ -1,81 +0,0 @@ -/* eslint-disable */ -/**柯礼钦 - * 4/2/2020, 11:22:51 AM - * doc comment for the file goes here - */ - -/** 菜单组件 */ - -import React from 'react'; -import { Spin, Layout, Menu, Icon } from 'antd'; -import MenView from '../../components/common/MenuView'; -import { menus, getMenuListByPermission } from '../../menu'; -import fetch from '../../api/request'; - -const { Sider } = Layout; - -function find(data, pathname) { - for (const { path, children } of data) { - if (path === pathname) return path; - if (children) { - const result = find(children, pathname); - if (result) return result; - } - } - return null; -} - -function selected(data, pathname) { - if (!pathname || pathname === '/') return pathname; - return find(data, pathname) || selected(data, pathname.split('/').slice(0, -1).join('/')); -} - -export default class MenuView extends React.Component { - constructor(props) { - super(props); - this.state = { - collapsed: true, - data: [] - }; - } - - componentWillMount() { - // 获取从登录页面记录在缓存里的菜单数据 - let menu = window.localStorage.getItem('menu') ? JSON.parse(window.localStorage.getItem('menu')) : []; - let permList = menu && menu.map(({ symbol }) => (symbol)).concat(menu.map(({ moduleSymbol }) => (moduleSymbol))).reduce((p, n) => { - if (p.indexOf(n) == -1) { - return p.concat(n) - } else { - return p - } - }, []); - // console.log(getMenuListByPermission(menus, permList) ) - this.setState({ data: getMenuListByPermission(menus, permList) }); - } - componentDidMount() { } - - onCollapse = collapsed => { - this.setState({ collapsed }); - } - - render() { - const { data, collapsed } = this.state; - const pathname = selected(data, this.props.location.pathname); - return ( - <Sider - onCollapse={this.onCollapse} - collapsed={collapsed} - breakpoint="lg" - collapsible={true} - > - <MenView - history={this.props.history} - pathname={pathname} - key={data.length} - menudata={data} - /> - </Sider> - ); - } - -} diff --git a/src/routeDom/oaRouteDom.jsx b/src/routeDom/oaRouteDom.jsx new file mode 100644 index 0000000..8533dee --- /dev/null +++ b/src/routeDom/oaRouteDom.jsx @@ -0,0 +1,42 @@ +/* eslint-disable */ +/**liuwh + * 5/26/2020, 4:44:40 PM + * doc comment for the file goes here + */ + +/** Happy Coding */ +import React, { ReactNode, ReactEventHandler, Component } from 'react'; +import { Switch, Route, Redirect } from 'react-router-dom'; + +// 引进页面(pages) +import Login from '../module/login/login'; +import Workbench from '../module/oa/index/workbench'; //首页--工作台 +import System from '../module/oa/index/System'; //首页--工作制度 +import Announcement from '../module/oa/index/Announcement'; //全部通知 + +import DocumentEdit from '../module/oa/document/DocumentEdit'; //新建文档 +import DocumentDetail from '../module/oa/document/DocumentDetail'; //文档详情 +import BrowseLog from '../module/oa/logManage/browseLog'; //浏览日志 +import OperLog from '../module/oa/logManage/operLog'; //操作日志 +import Rawler from '../module/oa/logManage/Rawler'; //爬虫词条管理 +import Information from '../module/oa/personal/information'; //个人信息 +import UserManage from '../components/oa/basicConfig/UserManage'; //用户管理 + +export default function OaRouteDom({ }) { + return (<Switch> + <Route path="/baseManage/user" component={UserManage} /> + <Route path="/document/create/:id?" component={DocumentEdit} /> + <Route path="/document/detail/:id" component={DocumentDetail} /> + <Route path="/index/workbench/announcement" component={Announcement} /> + <Route path="/index/rules" component={System} /> + <Route path="/index" component={Workbench} /> + <Route path="/logManage/browseLog" component={BrowseLog} /> + <Route path="/logManage/operLog" component={OperLog} /> + <Route path="/logManage/rawler" component={Rawler} /> + <Route path="/personal/information" component={Information} /> + <Route path="/login" component={Login} /> + {/* <Route path="/" component={Workbench} /> */} + <Redirect from="/" to="/index" component={Workbench} /> + </Switch> + ) +} diff --git a/src/routeDom/userRouteDom.jsx b/src/routeDom/userRouteDom.jsx new file mode 100644 index 0000000..c18a8c7 --- /dev/null +++ b/src/routeDom/userRouteDom.jsx @@ -0,0 +1,47 @@ +/* eslint-disable */ +/**liuwh + * 5/26/2020, 4:48:49 PM + * doc comment for the file goes here + */ + +/** Happy Coding */ +import React, { ReactNode, ReactEventHandler, Component } from 'react'; +import { Switch, Route, Redirect } from 'react-router-dom'; + +// 基础平台 +import UserManage from '../module/huge-base/UserManage'; //用户管理 +import UserDetail from '../module/huge-base/UserDetail'; //用户管理--用户详情 +import GroupManage from '../module/huge-base/GroupManage'; //组管理 +import GroupDetail from '../module/huge-base/GroupDetail'; //组管理--组详情 +import UnitManage from '../module/huge-base/UnitManage'; //组织管理--单位管理 +import DepartmentManage from '../module/huge-base/DepartmentManage'; //组织管理--部门管理 +import JobManage from '../module/huge-base/JobManage'; //组织管理--岗位管理 +import AppServiceManage from '../module/huge-base/AppServiceManage'; //资源管理--应用服务管理 +import AppServiceDetail from '../module/huge-base/AppServiceDetail'; //资源管理--应用服务管理详情 +import ModulesManage from '../module/huge-base/ModulesManage'; //资源管理--模块管理 +import FunctionManage from '../module/huge-base/FunctionManage'; //资源管理--功能管理 +import RoleManage from '../module/huge-base/RoleManage'; //权限管理--角色管理 +import RoleDetail from '../module/huge-base/RoleDetail'; //权限管理--角色管理详情 +import AuthorityManage from '../module/huge-base/AuthorityManage'; + +export default function UserRouteDom({ }) { + return ( + <Switch> + <Route path="/baseManage/user/Detail/:id/:flag" component={UserDetail} /> + <Route path="/baseManage/user" component={UserManage} /> + <Route path="/baseManage/group/Detail/:id/:flag" component={GroupDetail} /> + <Route path="/baseManage/group" component={GroupManage} /> + <Route path="/organizationMgt/unit" component={UnitManage} /> + <Route path="/organizationMgt/department" component={DepartmentManage} /> + <Route path="/organizationMgt/job" component={JobManage} /> + <Route path="/resourceMgt/appService/Detail/:id/:flag" component={AppServiceDetail} /> + <Route path="/resourceMgt/appService" component={AppServiceManage} /> + <Route path="/resourceMgt/modules" component={ModulesManage} /> + <Route path="/resourceMgt/function" component={FunctionManage} /> + <Route path="/organizationMgt/role/Detail/:id/:flag" component={RoleDetail} /> + <Route path="/authorityMgt/role" component={RoleManage} /> + <Route path="/authorityMgt/authority" component={AuthorityManage} /> + <Redirect from='/' to="/baseManage/user" component={UserManage} /> + </Switch> + ) +} diff --git a/src/style/reset.scss b/src/style/reset.scss index 0758323..3ca5aea 100644 --- a/src/style/reset.scss +++ b/src/style/reset.scss @@ -19,13 +19,13 @@ /*滚动条里面小方块*/ border-radius: 2.5px; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); - background: #848484; + background: #ccc; } *::-webkit-scrollbar-track { /*滚动条里面轨道*/ - box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); + box-shadow: inset 0 0 5px #fff; border-radius: 2.5px; - background: #ededed; + background: #fff; } .ant-layout { -- Gitblit v1.8.0