Commit 5de40c62 authored by 前端-许佳敏's avatar 前端-许佳敏

feat: 角色权限更改

parent 87431790
This diff is collapsed.
.field-header_container {
display: flex;
justify-content: space-between;
font-size: 14px;
margin-bottom: 18px;
}
.field-header_title {
display: flex;
align-items: center;
font-weight: 700;
&::before {
content: "";
width: 2px;
height: 14px;
background: #00B37A;
margin-right: 6px;
}
}
import React, { ReactNode } from 'react'
import mixinsClassName from 'classnames'
import './index.less'
export interface FieldHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
renderTitle: ReactNode,
extra?: ReactNode,
}
const FieldHeader:React.FC<FieldHeaderProps> = (props) => {
const { renderTitle, extra, className, ...restDivProps } = props
return (
<div className={mixinsClassName('field-header_container', className)} {...restDivProps}>
<div className='field-header_title'>{renderTitle}</div>
<div>{extra}</div>
</div>
)
}
FieldHeader.defaultProps = {}
export default FieldHeader
......@@ -2,7 +2,6 @@ import React from 'react';
import { Space } from 'antd';
const CustomStatus = props => {
console.log(props);
return (
<>
<Space>
......
import React, { useState, ReactText, useImperativeHandle, useEffect, useRef } from 'react'
import { Tree, Space, Tooltip, Button, Input } from 'antd'
import { findItemAndDelete, findTreeKeys, treeReduction, getParentTreeTitles } from '@/utils'
import './index.less'
import deepClone from 'clone'
import { TreeProps } from 'antd/lib/tree'
import { PlusOutlined, DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons'
import cx from 'classnames'
import { useSelections } from '@umijs/hooks'
import React, {
useState,
ReactText,
useImperativeHandle,
useEffect,
useRef,
} from 'react';
import { Tree, Space, Tooltip, Button, Input } from 'antd';
import {
findItemAndDelete,
findTreeKeys,
treeReduction,
getParentTreeTitles,
} from '@/utils';
import './index.less';
import deepClone from 'clone';
import { TreeProps } from 'antd/lib/tree';
import {
PlusOutlined,
DeleteOutlined,
PlusCircleOutlined,
} from '@ant-design/icons';
import cx from 'classnames';
import { useSelections } from '@umijs/hooks';
import FieldHeader from '../FieldHeader';
const { Search } = Input;
......@@ -18,8 +34,8 @@ export interface TabTreeActions {
setExpandedKeys: (keys: ReactText[]) => void;
setSelectKey: (key: ReactText) => void;
setSelectKeys: (keys: ReactText[]) => void;
getParentPath: (id: ReactText) => string
getParent: (id) => any
getParentPath: (id: ReactText) => string;
getParent: (id) => any;
}
export interface toolsRenderProps {
......@@ -78,8 +94,12 @@ export const createTreeActions = () => {
setSelectKey() {},
setSelectKeys() {},
setExpandedKeys() {},
getParentPath(id){return ''},
getParent(id){return null}
getParentPath(id) {
return '';
},
getParent(id) {
return null;
},
};
return actions;
};
......@@ -222,12 +242,12 @@ const TabTree: React.FC<TabTreeProps> = props => {
handleCheck,
customExpandkeys,
enableSearch = false,
searchPlaceholder = "搜索",
searchPlaceholder = '搜索',
checkStrictly = false,
resetSearch,
} = props;
const selfActions = useTreeActions(actions)
const selfActions = useTreeActions(actions);
// 需展开的key
const [expandkeys, setExpandkeys] = useState<ReactText[]>([]);
......@@ -235,17 +255,17 @@ const TabTree: React.FC<TabTreeProps> = props => {
const [selectKey, setSelectKey] = useState<string | number>('');
// 自动展开父级
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(false)
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(false);
// 搜索的值
const [searchValue, setSearchValue] = useState()
const [searchValue, setSearchValue] = useState();
useEffect(()=> {
if(resetSearch) {
setSearchValue(null)
setExpandkeys([])
useEffect(() => {
if (resetSearch) {
setSearchValue(null);
setExpandkeys([]);
}
}, [resetSearch])
}, [resetSearch]);
const data = transformSingleTitle(
deepClone(treeData),
......@@ -277,11 +297,11 @@ const TabTree: React.FC<TabTreeProps> = props => {
}, []);
useEffect(() => {
if(customExpandkeys?.length) {
setExpandkeys(customExpandkeys)
setAutoExpandParent(true)
if (customExpandkeys?.length) {
setExpandkeys(customExpandkeys);
setAutoExpandParent(true);
}
}, [customExpandkeys])
}, [customExpandkeys]);
const toggleSelectAll = () => {
if (allSelected) {
......@@ -306,50 +326,49 @@ const TabTree: React.FC<TabTreeProps> = props => {
setSelectKey(key);
};
selfActions.getParentPath = (id: ReactText) => {
return getParentTreeTitles(treeData, id)
}
return getParentTreeTitles(treeData, id);
};
selfActions.getParent = (id) => {
const reductData = treeReduction(treeData)
const targetInfo = reductData[id]
const parentInfo = reductData[targetInfo.parentId]
selfActions.getParent = id => {
const reductData = treeReduction(treeData);
const targetInfo = reductData[id];
const parentInfo = reductData[targetInfo.parentId];
// fixbug 当选中根节点下的节点时, 由于无parentId, 需自动补充0
return parentInfo || {id: 0}
}
return parentInfo || { id: 0 };
};
}
const batchSelect = (items: any) => {
if (items.checked) {
// 更改为严格模式
items.checked.forEach(v => select(v))
items.checked.forEach(v => select(v));
} else {
items.forEach(v => select(v))
items.forEach(v => select(v));
}
};
// 展开/收起的回调
const onExpand = expandedKeys => {
setAutoExpandParent(false)
setExpandkeys(expandedKeys)
setAutoExpandParent(false);
setExpandkeys(expandedKeys);
};
const onSearchChange = v => {
// todo 找到目标节点的父级key
setSearchValue(v)
if(v) {
const reductData = Object.values(treeReduction(treeData))
const expandedKeys = reductData.filter(item => item['title'].indexOf(v) > -1).map(_item => _item['parentId'])
setExpandkeys(expandedKeys)
setAutoExpandParent(true)
setSearchValue(v);
if (v) {
const reductData = Object.values(treeReduction(treeData));
const expandedKeys = reductData
.filter(item => item['title'].indexOf(v) > -1)
.map(_item => _item['parentId']);
setExpandkeys(expandedKeys);
setAutoExpandParent(true);
} else {
setExpandkeys([])
}
setExpandkeys([]);
}
};
return (
<div>
{title && (
<div className="god-tabtree-header">
<div>{title}</div>
const renderExtra = (
<>
{checkable && (
<Button onClick={toggleSelectAll} disabled={disabled} type="link">
{allSelected ? '取消全选' : '全选'}
......@@ -360,17 +379,20 @@ const TabTree: React.FC<TabTreeProps> = props => {
保存
</Button>
)}
</div>
)}
{
enableSearch && data?.length > 0 && <Search
</>
);
return (
<div>
{title && <FieldHeader renderTitle={title} extra={renderExtra} />}
{enableSearch && data?.length > 0 && (
<Search
style={{ marginBottom: 8 }}
placeholder={searchPlaceholder}
value={searchValue}
onChange={(v:any) => setSearchValue(v.target.value)}
onChange={(v: any) => setSearchValue(v.target.value)}
onSearch={onSearchChange}
/>
}
)}
<Tree
className="god-tabtree"
treeData={data}
......
import { Modal } from "antd"
import { ReactNode, useCallback, useEffect, useState } from "react"
export interface leaveOptions {
title?: ReactNode,
onSave: any,
onModalOk(resolve: any),
onModalCancel(reject: any),
}
/**
* 对即将离开某个操作时, 发出提示弹窗
*/
export const useLeavePage = (options: leaveOptions): [React.Dispatch<React.SetStateAction<boolean>>, any] => {
const { title, onSave, onModalOk, onModalCancel } = options
const [saveStatus, setSaveStatus] = useState<boolean>(true)
const validateSaveStatus = useCallback(() => {
if (saveStatus) {
return Promise.resolve()
} else {
return new Promise((resolve, reject) => {
Modal.confirm({
content: title || '确认要离开当前页面吗,您提交的数据尚未保存',
onOk() {
onModalOk(resolve)
},
onCancel() {
onModalCancel(reject)
}
})
})
}
}, [saveStatus])
return [setSaveStatus, validateSaveStatus]
}
import { useMap } from '@umijs/hooks'
import React, { useState, useEffect } from 'react'
import { Modal } from 'antd'
import { TabTreeActions } from '@/components/TabTree'
import { ISchemaFormActions } from '@formily/antd'
import { isObject } from '@/utils'
export enum FormState {
FREE, // 空闲状态
EDIT, // 编辑状态
ADD, // 新增状态
}
export interface useTreeTabOptions {
selectCallback?(selectKey?, node?),
fetchMenuData?(),
fetchItemDetailData?(id),
// 重置右侧详情
resetDetail?(),
// 对树形工具栏做render扩展
extendsToolsRender?: any,
// 树形的实例操作方法
treeActions?: TabTreeActions
// 右侧表单的实例操作方法
formActions?: ISchemaFormActions
// 删除菜单时调用的API
deleteMenu?: any
}
export interface treeNodeResponse {
/**
* 该节点是否选中
*/
selected: boolean,
/**
* 节点信息
*/
node: any
}
export const useTreeData = (options: useTreeTabOptions = {}) => {
const { selectCallback, fetchMenuData, treeActions, formActions, extendsToolsRender, deleteMenu } = options
const [treeExtraMaps, { set, get }] = useMap<any, any>()
const [treeData, setTreeData] = useState<any[]>([])
const [treeStatus, setTreeStatus] = useState<FormState>(FormState.FREE)
const [nodeRecord, setNodeRecord] = useState<any>(null)
const [isEditForm, setIsEditForm] = useState<boolean>(false)
useEffect(() => {
resetMenu()
}, [])
const resetMenu = async () => {
if (fetchMenuData) {
const res = await fetchMenuData()
setTreeData(res.data || [])
}
}
const handleSelect = (selectKey?, node?) => {
return new Promise<treeNodeResponse>((resolve, reject) => {
if (selectCallback) {
// 完全自定义点击节点事件
selectCallback(selectKey, node)
return;
}
resolve({
selected: true,
node: node || null
})
})
}
const handleDeleteMenu = (id) => {
deleteMenu({
id: isObject(id) ? nodeRecord.key : id
}).then(() => {
setTreeStatus(FormState.FREE)
setNodeRecord(undefined)
resetMenu()
})
}
// 新增整合树形操作菜单
// 树形工具栏
const toolsRender = {
addNode(node) {
const activeParentId = treeActions && treeActions.getParent(node.key || node.id)?.id
setNodeRecord({
...node,
parentId: activeParentId, // 添加同级的时候 使用上一级的id作为parentId
})
formActions && formActions.reset({ validate: false })
setTreeStatus(FormState.ADD)
},
addChildNode(node) {
setNodeRecord({
...node,
parentId: node.key || node.id
})
formActions && formActions.reset({ validate: false })
set(node.key || node.id, null)
setTreeStatus(FormState.ADD)
},
deleteNode(node) {
const id = node.key || node.id
handleDeleteMenu(id)
},
...extendsToolsRender
}
return {
handleSelect,
treeStatus,
setTreeStatus,
treeData,
setTreeData,
nodeRecord,
setNodeRecord,
isEditForm,
setIsEditForm,
treeExtraMaps,
setTreeMaps: set,
getTreeMaps: get,
resetMenu,
toolsRender,
handleDeleteMenu
}
}
.org-tag-container {
margin-bottom: 8px;
.ant-tag-has-color, .ant-tag-has-color a, .ant-tag-has-color a:hover, .ant-tag-has-color .anticon-close, .ant-tag-has-color .anticon-close:hover {
color: #606266;
}
}
.org-tag {
color: #606266;
}
import TabTree, { createTreeActions } from '@/components/TabTree'
import { useTreeTabs } from '@/hooks/useTreeTabs'
import { PublicApi } from '@/services/api'
import { Button, Drawer, Row } from 'antd'
import React, { useEffect, useState } from 'react'
import './orgModal.less'
export interface OrgModalProps {
visible: boolean,
handleSyncSelect: any,
plateformTreeData: any,
fetchOrgsTreeData: any,
selectKeys: any[],
onSuccess(selectKeys: any[]),
onCancel(),
}
const syncTreeActions = createTreeActions()
const OrgModal:React.FC<OrgModalProps> = (props) => {
const { visible, onSuccess, onCancel, plateformTreeData, handleSyncSelect, fetchOrgsTreeData, selectKeys } = props
const [resetSearch, setResetSearch] = useState(false)
const [customPlateformExpandkeys, setCustomPlateformExpandkeys] = useState<any>()
const handleSuccess = () => {
onSuccess(syncTreeActions.getSelectKeys())
}
useEffect(() => {
syncTreeActions.setSelectKeys(selectKeys)
}, [selectKeys])
return (
<Drawer
visible={visible}
closable={false}
placement='right'
width={600}
>
<TabTree
fetchData = {params => fetchOrgsTreeData()}
treeData={plateformTreeData}
handleSelect={handleSyncSelect}
actions={syncTreeActions}
customKey="id"
enableSearch
searchPlaceholder="组织机构名称"
checkStrictly
resetSearch={resetSearch}
customExpandkeys={customPlateformExpandkeys}
checkable={true}
/>
<Row justify='end'>
<Button onClick={onCancel} style={{marginRight: 8}}>关闭</Button>
<Button onClick={handleSuccess} type='primary'>确认</Button>
</Row>
</Drawer>
)
}
OrgModal.defaultProps = {}
export default OrgModal
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment