Browse Source

组织管理添加、删除、重置、启禁用接口对接

zhouna 3 years ago
parent
commit
f4c6cb5157

+ 6 - 0
src/api/request.js

@@ -9,5 +9,11 @@ const request = {
     updateHospital:'/security-center/hospitalManage/updateHospital',   //修改
     getHospitalById:'/security-center/hospitalManage/getHospitalById', //获取详情
     getUserPage:'/security-center/userManage/getUserPage',//用户列表
+    resetPassword:'/security-center/hospitalManage/resetPassword',  //重置密码
+    //角色管理相关接口
+    getUserMenuResourceTree:'/security-center/roleManage/getUserMenuResourceTree',      //获取菜单权限树
+
+    //用户管理相关接口
+    getHospitalTree:"/security-center/userManage/getHospitalTree",
 };
 export default request;

+ 2 - 2
src/components/ATabs/index.less

@@ -2,6 +2,6 @@
 
 .tab-container{
   background: @bg-color;
-  padding: 10px 12px;
-  margin:12px;
+  padding: 0 12px 10px;
+  margin:0 12px;
 }

+ 274 - 14
src/components/OrgManager/AddSubOrg.js

@@ -1,7 +1,16 @@
-import {useEffect,useState} from 'react';
-import { Form, Input, Button, Radio, Select,Steps,DatePicker,InputNumber,TreeSelect,Switch, } from 'antd';
+import {useEffect,useState,useContext} from 'react';
+import { Form, Input, Checkbox, Button, Select,Steps,Tabs ,InputNumber,Space,Switch, } from 'antd';
+import MenuTree  from './MenuTree';
 import './index.less';
+import OrgContext from './org-context';
+import {message} from "antd/lib/index";
+import apiObj from '@api/index';
+
+const {post,api,xPost} = apiObj;
+
 const { Step } = Steps;
+const { TabPane } = Tabs;
+const { Option } = Select;
 function AddSubOrg(){
     const [current, setCurrent] = useState(0);
     const steps = [
@@ -22,6 +31,9 @@ function AddSubOrg(){
     const next = () => {
         setCurrent(current + 1);
     };
+    const pre = () => {
+        setCurrent(current - 1);
+    };
     return (
         <div className="add-container">
             <Steps current={current} labelPlacement='vertical'>
@@ -29,42 +41,290 @@ function AddSubOrg(){
                     <Step key={item.title} title={item.title} />
                 ))}
             </Steps>
-            <div className="steps-content"><FirstStep /></div>
+            <div className="steps-content">
+                <StepContent current={current}
+                    pre={pre}
+                    next={next}
+                />
+            </div>
         </div>
     )
 }
 
-function FirstStep(){
+function StepContent(props){
+    const [form] = Form.useForm();
+    const [treeDatas, setTreeDatas] = useState([]);
+    const [tabDatas, setTabDatas] = useState([]);
+    const [activeTab, setActiveTab] = useState('');
+    const [sysCheckeds, setSysCheckeds] = useState([]);
+    const {orgId,orgName,typeList,save}  = useContext(OrgContext);
+    const {current,pre,next} = props;
+    const initialValues={
+        parentId:orgId,
+        parentName:orgName,
+        status:1
+    };
+    const vilidateRules = {
+        required: '${label}不能为空!',
+        types: {
+            email: '${label} is not a valid email!',
+            number: '${label} is not a valid number!',
+        },
+    };
+
+    //获取菜单数据
+    function getTreeData(){
+        xPost(api.getUserMenuResourceTree,{type:0}).then((res)=>{
+            if(res.data.code===200){
+                const data = res.data.data;
+                const treeDatas = structureTreeData(data);
+                setTreeDatas(treeDatas);
+                setTabDatas([treeDatas[0]]);
+                setActiveTab(treeDatas[0].key);
+            }
+
+        })
+    }
+    //数据转换为树形结构所需字段
+    function structureTreeData(data){
+        const arr = [];
+        let obj={};
+        data.map((it,i)=>{
+            obj =JSON.stringify(it.children).replace(/softwareMenuId/g,"key").replace(/menuName/g,'title');
+            arr[i]={
+                title:it.softwareName,
+                key:it.softwareId,
+                children:JSON.parse(obj)
+            }
+        });
+        setSysCheckeds(arr[0]?[arr[0].key]:[]);
+        //form.setFieldsValue({softwares:[{id:arr[0]?[arr[0].key]:''}]});   //默认选中第一个
+        return arr;
+    }
+    useEffect(()=>{
+        getTreeData();
+    },[]);
+    function handlePre(){
+        pre();
+    }
+    function handleNext(){
+        const validateKeys = {
+            0:['parentId','name','code',['addHospitalUserVO','name'],['addHospitalUserVO','mobilePhone'],'type','orderNo'],
+            1:[['addHospitalUserVO','username'],['addHospitalUserVO','password'],'confirmPsd'],
+        };
+        form.validateFields(validateKeys[current]).then((res)=>{
+            //console.log(res,form)
+            next(form);
+        });
+    }
+    function handleSave(){
+        form.validateFields([['softwares',0,'id'],['softwares',0,'softwareMenuIds'],['softwares',0,'softwareResourceIds']]).then((res)=>{
+            save(form.getFieldsValue())
+        });
+
+    }
+    //树形结构选中事件
+    function checkTreeEvent(i,idsArr,sourceIds){
+        console.log(32,i,idsArr,sourceIds,activeTab)
+        const formData=form.getFieldsValue();
+        const arr=formData.softwares;
+        arr[i]={
+            id:activeTab,
+            softwareMenuIds:idsArr,
+            softwareResourceIds:sourceIds
+        };
+        form.setFieldsValue({
+            softwares:arr
+        });
+    }
+    function onTabChange(activeTab){
+        setActiveTab(activeTab)
+    }
+    //状态开关
+    function switchStatus(checked){
+        form.setFieldsValue({
+            status:checked?1:0
+        });
+    }
+    //开放系统勾选事件
+    function softwareChange(checkedValue){
+        let arr = [],item;
+        setSysCheckeds(checkedValue);
+        for(let i=0;i<checkedValue.length;i++){
+            item=treeDatas.find((it)=>it.key===checkedValue[i]);
+            if(item){
+                arr.push(item);
+            }
+        }
+        setTabDatas(arr);
+    }
     return (
+        <>
         <Form
             labelCol={{ span: 6 }}
             wrapperCol={{ span: 16 }}
             layout="horizontal"
+            validateMessages={vilidateRules}
+            initialValues={initialValues}
+            form={form}
         >
-            <Form.Item label="上级组织">
-                <Input disabled required/>
+            <Form.Item
+                label="上级组织ID"
+                hidden={true}
+                name='parentId'>
+                <Input  placeholder='请输入上级组织ID'/>
             </Form.Item>
-            <Form.Item label="组织名称">
-                <Input placeholder='请输入组织名称' required/>
+            <Form.Item
+                label="上级组织"
+                name='parentName'
+                hidden={current!==0}
+                rules={[{ required: true}]}>
+                <Input disabled/>
             </Form.Item>
-            <Form.Item label="组织编码">
+            <Form.Item
+                label="组织名称"
+                name='name'
+                hidden={current!==0}
+                rules={[{ required: true},({ getFieldValue }) => ({
+                    validator(_, value) {
+                        if (value.length<51) {
+                            return Promise.resolve();
+                        }
+                        return Promise.reject(new Error('格式错误!'));
+                    },
+                }),]}>
+                <Input placeholder='请输入组织名称'/>
+            </Form.Item>
+            <Form.Item
+                label="组织编码"
+                hidden={current!==0}
+                name='code'>
                 <Input placeholder='请输入组织编码' />
             </Form.Item>
-            <Form.Item label="联系人">
+            <Form.Item
+                label="联系人"
+                hidden={current!==0}
+                name={['addHospitalUserVO','name']}>
                 <Input  placeholder='请输入联系人'/>
             </Form.Item>
-            <Form.Item label="手机号码">
+            <Form.Item
+                label="手机号码"
+                hidden={current!==0}
+                name={['addHospitalUserVO','mobilePhone']}>
                 <Input  placeholder='请输入手机号码'/>
             </Form.Item>
-            <Form.Item label="类型">
+            <Form.Item
+                label="类型"
+                name='type'
+                hidden={current!==0}
+                rules={[{ required: true }]}>
                 <Select placeholder='请选择类型'>
-                    <Select.Option value="demo">Demo</Select.Option>
+                    <Option value="">全部</Option>
+                    {typeList.map((item)=>{
+                        return (
+                            <Option value={item.name} key={item.name}>{item.val}</Option>
+                        )
+                    })}
                 </Select>
             </Form.Item>
-            <Form.Item label="排序">
+            <Form.Item
+                label="排序"
+                hidden={current!==0}
+                name='orderNo'>
                 <InputNumber placeholder='大于0的整数' min={0}/>
             </Form.Item>
+            <Form.Item
+                label="用户名"
+                hidden={current!==1}
+                name={['addHospitalUserVO','username']}
+                rules={[{ required: true}]}>
+                <Input placeholder='请输入用户名'/>
+            </Form.Item>
+            <Form.Item
+                label="初始密码"
+                type="password"
+                hidden={current!==1}
+                name={['addHospitalUserVO','password']}
+                rules={[{ required: true}]}>
+                <Input placeholder='请输入初始密码'/>
+            </Form.Item>
+            <Form.Item
+                label="确认密码"
+                type="password"
+                name='confirmPsd'
+                dependencies={['addHospitalUserVO','password']}
+                hidden={current!==1}
+                rules={[{ required: true},({ getFieldValue }) => ({
+                    validator(_, value) {
+                        if (!value || getFieldValue(['addHospitalUserVO','password']) === value) {
+                            return Promise.resolve();
+                        }
+                        return Promise.reject(new Error('两次密码输入不一致!'));
+                    },
+                }),]}>
+                <Input placeholder='请输入确认密码'/>
+            </Form.Item>
+            <Form.Item
+                label="开放系统"
+                type="password"
+                hidden={current!==2}
+                rules={[{ required: true}]}>
+                <Checkbox.Group value={sysCheckeds} onChange={softwareChange}>
+                {
+                    treeDatas.map((it, i) => {
+                        return (
+                                <Form.Item key={it.key} noStyle>
+                                    <Checkbox key={i} value={it.key}>{it.title}</Checkbox>
+                                </Form.Item>
+                        )
+                    })
+                }
+                </Checkbox.Group>
+            </Form.Item>
+            <Form.Item
+                label="菜单权限"
+                hidden={current!==2}
+                required>
+                <Tabs onChange={onTabChange} type="card">
+                    {
+                        tabDatas.map((it,i)=>{
+                            console.log(0,it,i,tabDatas)
+                            return (
+                                <TabPane tab={it.title} key={i}>
+                                    <Form.Item key={i} name={['softwares', i, 'softwareMenuIds']} noStyle>
+                                        <MenuTree data={it} checkEv={(checkedKeys,sourceIds)=>checkTreeEvent(i,checkedKeys,sourceIds)}/>
+                                    </Form.Item>
+                                    <Form.Item key={i+"a"} hidden={true} name={['softwares', i, 'id']} noStyle>
+                                        <Input/>
+                                    </Form.Item>
+                                    <Form.Item key={i+"b"} hidden={true} name={['softwares', i, 'softwareResourceIds']} noStyle>
+                                        <Input/>
+                                    </Form.Item>
+                                </TabPane>
+                            )
+                        })
+                    }
+                </Tabs>
+            </Form.Item>
+            <Form.Item
+                label="当前状态"
+                hidden={current!==2}>
+                <Space>
+                    <Form.Item
+                        name='status'
+                        noStyle>
+                        <Switch checked={form.status} onChange={switchStatus} />
+                    </Form.Item>
+                    <span>启用</span>
+                </Space>
+            </Form.Item>
         </Form>
+        <div className="button-box">
+            {current!==0?<Button onClick={handlePre}>上一步</Button>:null}
+            {current!==2?<Button onClick={handleNext} type='primary'>下一步</Button>:null}
+            {current===2?<Button onClick={handleSave} type='primary'>保存</Button>:null}
+        </div>
+        </>
     )
 }
 

+ 35 - 0
src/components/OrgManager/MenuTree.js

@@ -0,0 +1,35 @@
+import { useState,useEffect } from 'react';
+import apiObj from '@api/index';
+import { Tree  } from 'antd';
+
+//const { post,api } = apiObj;
+function MenuTree(props){
+    const {data,checkEv} = props;
+
+    //菜单选中事件
+    function onCheck(checkedKeys,e){
+        const {checkedNodes} = e;
+        const sourceIds  = [];
+        checkedNodes.map((it)=>{
+            if(it.softwareResourceId){
+                sourceIds.push(it.softwareResourceId);
+            }
+        });
+        checkEv(checkedKeys,sourceIds)
+        console.log(211,checkedKeys,sourceIds)
+    }
+    function onSelect(){
+
+    }
+    const treeData = data?[data]:null;
+    return (
+        <Tree
+            checkable
+            onCheck={onCheck}
+            onSelect={onSelect}
+            treeData={treeData}
+        />
+    )
+}
+
+export default MenuTree;

+ 54 - 31
src/components/OrgManager/index.js

@@ -1,14 +1,13 @@
 import {useEffect,useState} from 'react';
-import { useDispatch,useSelector } from 'react-redux'
+/*import { useDispatch,useSelector } from 'react-redux'*/
 import { Table,Modal, message, Menu, Breadcrumb, Dropdown, Space, Form, Input, Button, Row, Col, Select } from 'antd';
 import { DownOutlined,PlusOutlined } from '@ant-design/icons';
 import AddSubOrg from './AddSubOrg';
 import './index.less';
 import apiObj from '@api/index';
-import utils from '@utils/index';
+import OrgContext from './org-context';
 
 const {post,api,xPost} = apiObj;
-const { handleResponse } = utils;
 const { Option } = Select;
 function OrgManager(){
     useEffect(() => {
@@ -21,17 +20,19 @@ function OrgManager(){
     const [visible,setVisible] = useState(false);
     const [addVisible,setAddVisible] = useState(false);
     const [confirmLoading, setConfirmLoading] = useState(false);
-    //弹窗类型:1删除 2有子组织删除 3有用户删除 4禁用 5有子组织禁用 6有用户禁用 7重置密码
+    //弹窗类型:1删除 2有子组织、用户删除 3禁用 4有子组织、用户禁用 5重置密码
     const [modalType,setModalType] = useState(1);
+    const [modalTitle,setModalTitle] = useState(1);
     const [operId,setOperId] = useState('');
+    const [orgId,setOrgId] = useState('');
+    const [orgName,setOrgName] = useState('');
+
     const tipText={
         1:'确定要删除该组织?',
-        2:'当前组织存在子组织,删除后子组织将一并被删除',
-        3:'当前组织或子组织存在用户,删除后用户将一并被删除',
-        4:'确定要禁用该组织?',
-        5:'当前组织存在子组织,禁用后子组织将一并被禁用',
-        6:'当前组织或子组织存在用户,禁用后用户将一并被禁用',
-        7:'确定要重置该组织密码?',
+        2:'当前组织内可能包含子组织或其相关用户,删除后所包含信息将一并被删除',
+        3:'确定要禁用该组织?',
+        4:'当前组织内可能包含子组织或其相关用户,禁用后所包含信息将一并被禁用',
+        5:'确定要重置该组织密码?',
     };
 
     //获取筛选下拉数据
@@ -39,7 +40,7 @@ function OrgManager(){
         post(api.getManagerBoxInfo).then((res)=>{
             if(res.data.code===200){
                 const data = res.data.data;
-                setTypeList(data["类型"]);
+                setTypeList(data[43]);
             }
         })
     }
@@ -48,17 +49,20 @@ function OrgManager(){
         post(api.getHospitalListInfo,param).then((res)=>{
             if(res.data.code===200){
                 const data = res.data.data;
+                setOrgId(data[0]?data[0].hospitalId:'');
+                setOrgName(data[0]?data[0].hospitalName:'')
                 setDataSource(data);
             }
 
         })
     }
     //启用/禁用
-    function enable(flag) {
-        const param = {HospitalId:operId,status:flag};
+    function enable(flag,id) {
+        const param = {HospitalId:id||operId,status:flag};
         xPost(api.disableHospital,param).then((res)=>{
             if(res.data.code===200){
                 getTableData();
+                setVisible(false);
                 message.success((flag?'启用':'禁用')+"成功");
             }else{
                 message.warning(res.data.msg||'操作失败');
@@ -70,9 +74,10 @@ function OrgManager(){
     //重置密码
     function onResetPsd(){
         const param = {HospitalId:operId};
-        xPost(api.disableHospital,param).then((res)=>{
+        xPost(api.resetPassword,param).then((res)=>{
             if(res.data.code===200){
                 getTableData();
+                setVisible(false)
                 message.success("重置成功");
             }else{
                 message.warning(res.data.msg||'操作失败');
@@ -87,6 +92,7 @@ function OrgManager(){
         xPost(api.deleteHospital,param).then((res)=>{
             if(res.data.code===200){
                 getTableData();
+                setVisible(false);
                 message.success("删除成功");
             }else{
                 message.warning(res.data.msg||'操作失败');
@@ -102,12 +108,12 @@ function OrgManager(){
         setVisible(true);
     }
     //弹窗确认事件
-    function handleOk(type){
-        if("1,2,3".indexOf(type)>-1){
+    function handleOk(){
+        if("1,2".indexOf(modalType)>-1){
             onDelete();
-        }else if("4,5,6".indexOf(type)>-1){
+        }else if("3,4".indexOf(modalType)>-1){
             enable(0);
-        }else if(type===7){
+        }else if(modalType===5){
             onResetPsd();
         }
 
@@ -115,11 +121,29 @@ function OrgManager(){
     //弹窗取消
     function handleCancel(){
         setVisible(false);
+        setAddVisible(false);
     }
     //新增子组织弹窗
-    function showAddModal(){
+    function showAddModal(title){
+        setModalTitle(title);
         setAddVisible(true);
     }
+    //保存
+    function addSubOrg(formData){
+        console.log('保存参数:',formData);
+        const param = formData;
+        post(api.addHospital,param).then((res)=>{
+            if(res.data.code===200){
+                getTableData();
+                setAddVisible(false);
+                message.success("添加成功");
+            }else{
+                message.warning(res.data.msg||'操作失败');
+            }
+        }).catch(()=>{
+            message.error("接口出错");
+        });
+    }
     //表格渲染
     function RenderTable(){
         const columns = [
@@ -146,13 +170,13 @@ function OrgManager(){
                 }
                 const menu = (
                     <Menu>
-                        <Menu.Item key="0" onClick={(row)=>showModal(7,row.hospitalId)}>重置密码</Menu.Item>
-                        <Menu.Item key="1" onClick={(row)=>showModal(1,row.hospitalId)}>删除</Menu.Item>
+                        <Menu.Item key="0" onClick={()=>showModal(5,row.hospitalId)}>重置密码</Menu.Item>
+                        <Menu.Item key="1" onClick={()=>showModal((row.hasUserFlag||row.hasHospitalFlag?2:1),row.hospitalId)}>删除</Menu.Item>
                     </Menu>
                 );
                 return (<Space size="middle">
                     <a>修改</a>
-                    {row.status==='1'?(<a onClick={()=>showModal(4,row.hospitalId)}>禁用</a>):(<a onClick={()=>enable(row,1)}>启用</a>)}
+                    {row.status==='1'?(<a onClick={()=>showModal(row.hasUserFlag||row.hasHospitalFlag?4:3,row.hospitalId)}>禁用</a>):(<a onClick={()=>enable(1,row.hospitalId)}>启用</a>)}
                     <Dropdown overlay={menu} trigger={['click']}>
                         <a className="ant-dropdown-link">
                             更多 <DownOutlined />
@@ -179,7 +203,6 @@ function OrgManager(){
         form.resetFields();
         getTableData();
     };
-
     return (
         <div className='container'>
             <div className="filter-box">
@@ -197,11 +220,11 @@ function OrgManager(){
                                     allowClear
                                 >
                                     <Option value="">全部</Option>
-                                    {/*{typeList.map((item)=>{
+                                    {typeList.map((item)=>{
                                         return (
-                                            <Option value={item.value}>{item.name}</Option>
+                                            <Option value={item.name}  key={item.name}>{item.val}</Option>
                                         )
-                                    })}*/}
+                                    })}
                                 </Select>
                             </Form.Item>
                         </Col>
@@ -234,7 +257,7 @@ function OrgManager(){
                     <Breadcrumb>
                         <Breadcrumb.Item>组织管理</Breadcrumb.Item>
                     </Breadcrumb>
-                    <Button type="primary" icon={<PlusOutlined />} onClick={e => showAddModal('新增子组织', true)}>新增子组织</Button>
+                    <Button type="primary" icon={<PlusOutlined />} onClick={()=> showAddModal('新增子组织')}>新增子组织</Button>
                 </div>
                 <RenderTable />
             </div>
@@ -251,16 +274,16 @@ function OrgManager(){
                 <p>{tipText[modalType]}</p>
             </Modal>
             <Modal
-                title="提示"
-                okText='确定'
-                cancelText='取消'
+                title={modalTitle}
+                footer={null}
                 width={690}
                 visible={addVisible}
-                onOk={handleOk}
                 confirmLoading={confirmLoading}
                 onCancel={handleCancel}
             >
+            <OrgContext.Provider value={{orgId,orgName,typeList,save:addSubOrg}}>
                 <AddSubOrg />
+            </OrgContext.Provider>
             </Modal>
         </div>
     )

+ 19 - 0
src/components/OrgManager/index.less

@@ -13,9 +13,28 @@
 .ant-steps-item-title{
   font-size: 14px;
 }
+.ant-tabs > .ant-tabs-nav, .ant-tabs > div > .ant-tabs-nav{
+  margin-bottom: 0;
+}
+.ant-tabs-content-holder{
+  border: 1px solid #f0f0f0;
+  border-top: none;
+}
 .steps-content{
   margin-top:40px ;
 }
+.button-box{
+  text-align: right;
+  .ant-btn-primary{
+    margin-left: 20px;
+  }
+}
+.filter-box{
+  .ant-btn-primary{
+    margin-right: 20px;
+  }
+}
+
 
 .table-header{
   display: flex;

+ 4 - 0
src/components/OrgManager/org-context.js

@@ -0,0 +1,4 @@
+import {createContext} from 'react';
+const OrgContext = createContext(null);
+
+export default OrgContext;