Commit 4a35cdb2 authored by 前端-许佳敏's avatar 前端-许佳敏

权限平台

parent df3e7736
......@@ -128,6 +128,28 @@ const router = [
},
],
},
{
path: '/authConfig',
name: 'authConfig',
icon: 'SmileOutlined',
routes: [
{
path: '/authConfig/organ',
name: 'organ',
component: '@/pages/authConfig/organ',
},
{
path: '/authConfig/memberSystem',
name: 'memberSystem',
component: '@/pages/authConfig/memberSystem',
},
{
path: '/authConfig/userSystem',
name: 'userSystem',
component: '@/pages/authConfig/userSystem',
},
],
},
],
},
];
......
export default {
path: '/authConfig',
name: 'authConfig',
icon: 'SmileOutlined',
routes: [
{
path: '/authConfig/organ',
name: 'organ',
component: '@/pages/authConfig/organ',
},
{
path: '/authConfig/memberSystem',
name: 'memberSystem',
component: '@/pages/authConfig/memberSystem',
},
{
path: '/authConfig/memberSystem/memberDetail',
name: 'memberDetail',
component: '@/pages/authConfig/memberSystem/memberDetail',
},
{
path: '/authConfig/userSystem',
name: 'userSystem',
component: '@/pages/authConfig/userSystem',
},
{
path: '/authConfig/userSystem/userDetail',
name: 'userSystem',
component: '@/pages/authConfig/userSystem/userDetail',
},
],
}
\ No newline at end of file
......@@ -15,7 +15,8 @@ import commodity from './commodityRoute' // 商品审核路由
import logisticsRoutes from './logisticsRoutes'
import memberAbility from './memberAbility'
import ruleSettingRoutes from './ruleSettingRoutes'
const routeList = [pageCustomized, calssPropertyRoute, trademarkRoute, commodity, logisticsRoutes, memberAbility, ruleSettingRoutes]
import authConfig from './authConfig'
const routeList = [pageCustomized, calssPropertyRoute, trademarkRoute, commodity, logisticsRoutes, memberAbility, ruleSettingRoutes, authConfig]
const router = [
{
path: '/login',
......
......@@ -11,7 +11,7 @@ export interface StatusSwitchProps {
}
const StatusSwitch: React.FC<StatusSwitchProps> = props => {
const { record, fieldNames = 'state', expectTrueValue = 1 } = props;
const { record, fieldNames = 'status', expectTrueValue = 1 } = props;
return (
<Popconfirm
title="确定要执行这个操作?"
......
This diff is collapsed.
export const NOT_CHANGE_VALUE = 'hello, world'
\ No newline at end of file
export const NOT_CHANGE_VALUE = 'hello, world'
export const isDev = true
\ No newline at end of file
import { history } from 'umi'
const events = {}
export const useEvent = () => {
const register = (callback) => {
events[history.location.path] = callback
}
const get = (key) => register[key]
const emit = () => {
register[history.location.path].call(null)
}
return {
register,
get,
emit
}
}
import React, { createContext } from 'react'
export const historyContainer = createContext<any>(null);
import React, { useState } from 'react';
import { IApiRequest } from '@/utils/request';
import { useRouter } from './useRouter';
export interface IHttpRequestReturn<T> {
data: T | null,
......@@ -12,15 +13,21 @@ export interface IHttpRequestReturn<T> {
* 简易版本的useRequest hooks, 用于处理带有loading的业务场景
* @auth xjm
*/
export function useHttpRequest<T>(api: (params?, config?) => Promise<T>, config?: IApiRequest): IHttpRequestReturn<T> {
export function useHttpRequest<T>(api: (params?, config?) => Promise<T>, config?: IApiRequest & {back?: boolean}): IHttpRequestReturn<T> {
const [loading, setLoading] = useState(false)
const [data, setData] = useState<T | null>(null)
const [err, setErr] = useState()
const { goBack } = useRouter()
const run = (params) => {
setLoading(true)
api(params).then((res: any) => {
setData(res.data)
if (config && config.back) {
setTimeout(() => {
goBack()
}, 1000)
}
}).catch(err => {
setErr(err)
}).finally(() => {
......
......@@ -8,7 +8,7 @@ export enum PageStatus {
}
export const usePageStatus = () => {
const { preview, id = '', validateId = '' } = history.location.query
const { preview, id = '' } = history.location.query
// 默认预览状态
let pageStatus = PageStatus.PREVIEW
if (preview === '1') {
......@@ -24,7 +24,6 @@ export const usePageStatus = () => {
return {
pageStatus,
id,
preview,
validateId
preview
}
}
\ No newline at end of file
import { history } from 'umi'
import { useState } from 'react'
export const useRouter = () => {
const goBack = () => {
history.goBack()
}
return {
goBack
}
}
\ No newline at end of file
import { useState } from 'react'
import { TableRowSelection } from 'antd/es/table/interface'
import { mergeArrByKey, dupliArr } from '@/utils'
import { useSelections } from '@umijs/hooks'
interface useRowSelectionTableCtl {
selectRow: any[],
......@@ -18,16 +20,58 @@ interface useRowSelectionOptions {
*/
export const useRowSelectionTable = (options: useRowSelectionOptions = {}): [TableRowSelection<any>, useRowSelectionTableCtl] => {
const { type = 'checkbox' } = options
const [selectRow, setSelectRow] = useState<any[]>([]) // 模态框选择的行数据
const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>(() => [])
const mergeRowKeys = (item) => {
setSelectedRowKeys([...selectedRowKeys, item])
}
const mergeRow = (item) => {
setSelectRow([...selectRow, item])
}
const removeRows = (arr: any[]) => {
return selectRow.filter(v => {
const result = arr.find(item => item.id === v.id)
if (!result) {
return v
}
})
}
const removeRowsKeys = (arr: any[]) => {
return selectedRowKeys.filter(v => {
const result = arr.find(item => item === v)
if (!result) {
return v
}
})
}
const rowSelection = {
selectedRowKeys: selectedRowKeys,
type,
onChange: (selectedRowKeys: any, selectedRows: any) => {
setSelectRow(selectedRows);
setSelectedRowKeys(selectedRowKeys);
// 为解决分页情况下, 保存多选的数据
onSelect: (record, selects, selectedRows, nativeEvent) => {
const findIds = selectedRowKeys.indexOf(record.id)
if (findIds === -1) {
mergeRowKeys(record.id)
mergeRow(record)
} else {
setSelectedRowKeys(selectedRowKeys.filter((_, i) => i !== findIds))
setSelectRow(selectRow.filter((_, i) => i !== findIds))
}
},
onSelectAll: (selected, selectedRows, changeRows) => {
if (selected) {
setSelectedRowKeys(dupliArr([...selectedRowKeys, ...changeRows.map(v => v.id)]))
setSelectRow(mergeArrByKey(selectRow, changeRows, 'id'))
} else {
setSelectedRowKeys(removeRowsKeys(changeRows.map(v => v.id)))
setSelectRow(removeRows(changeRows))
}
}
}
......
export interface simpleCurdOptions {
add(params),
delete(params),
find(params),
update(params),
changeStatus(params)
}
/**
* @todo 简单的增删改查hooks, 可以配合table进行某些重复的操作
*/
export const useSimpleCurd = (options) => {
}
\ No newline at end of file
......@@ -17,10 +17,10 @@ export interface useTreeTabOptions {
export const useTreeTabs = (options: useTreeTabOptions = {}) => {
const { selectCallback, fetchMenuData, fetchItemDetailData, resetDetail } = 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 [ 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)
......@@ -33,18 +33,18 @@ export const useTreeTabs = (options: useTreeTabOptions = {}) => {
setTreeData(res.data || [])
}
}
const handleSelect = (selectKey?, node?) => {
if (selectCallback) {
selectCallback(selectKey, node)
return;
return ;
}
// 首次新增菜单的时候没有节点信息
if (!node) {
// 首次新增菜单的时候没有节点信息
if (!node) {
setNodeRecord(null)
setTreeStatus(FormState.ADD)
return;
return ;
}
// key相等时 不刷新右侧表单
if (nodeRecord && nodeRecord.key === selectKey) {
......@@ -81,7 +81,7 @@ export const useTreeTabs = (options: useTreeTabOptions = {}) => {
}
const handleFindDetail = (id) => {
fetchItemDetailData && fetchItemDetailData(id).then(res => {
fetchItemDetailData && fetchItemDetailData({id}).then(res => {
const { data } = res
set(id, data)
})
......
import React from 'react'
import { Link } from 'umi'
import { Link, history } from 'umi'
import { Menu, Dropdown } from 'antd'
import { CaretDownOutlined } from '@ant-design/icons'
import styles from './index.less'
import { removeAuth } from '@/utils/auth'
const RightContent: React.FC<{}> = (props) => {
const toLogin = () => {
removeAuth()
history.replace('/login')
}
const menu = (
<Menu>
<Menu.Item>
密码修改
</Menu.Item>
<Menu.Item>
<Menu.Item onClick={toLogin}>
退出登录
</Menu.Item>
</Menu>
......
import React from 'react';
import React, { useState, ReactComponentElement } from 'react';
import styles from '../index.less'
export interface IPageHeader {
title?: string,
routeInfo?: any
title?: React.ReactNode,
routeInfo?: any,
extra?: React.ReactNode
}
const PageHeader: React.FC<IPageHeader> = (props: IPageHeader) => {
const { routeInfo } = props
if (routeInfo?.hidePageHeader) {
if (routeInfo && routeInfo.hidePageHeader) {
return null
}
return <div className={styles.lxPageHeader}>{props.title}</div>
return <div className={styles.lxPageHeader}>
<div>{props.title}</div>
{props.extra}
</div>
}
PageHeader.defaultProps = {
......
......@@ -49,6 +49,10 @@ export default {
'menu.pageCustomized.shopCenterTemplate': '商城模版',
'menu.pageCustomized.shopTemplate': '店铺模版',
'menu.pageCustomized.templateDetail': '模版详情',
'menu.authConfig': '平台权限',
'menu.authConfig.organ': '组织机构',
'menu.authConfig.memberSystem': '角色管理',
'menu.authConfig.userSystem': '用户管理',
// 会员能力
'menu.memberAbility': '会员管理',
'menu.memberAbility.memberMaintain': '会员维护',
......
.menu-role-tree {
padding: 24px;
border: 1px solid #F4F5F7;
}
\ No newline at end of file
import React, { ReactNode, useRef } from 'react';
import { history, Link } from 'umi'
import { Button, Popconfirm } from 'antd';
import {
PlusCircleOutlined,
PlayCircleOutlined,
PauseCircleOutlined,
PlusOutlined,
EyeOutlined
} from '@ant-design/icons';
import {StandardTable} from 'god'
import {ColumnType} from 'antd/lib/table/interface'
import { IButtonFilter, IFormFilter } from 'god/dist/src/standard-table/TableController';
import { PublicApi } from '@/services/api';
import StatusSwitch from '@/components/StatusSwitch';
import EyePreview from '@/components/EyePreview';
const fetchData = async (params) => {
const { data } = await PublicApi.getMemberRolePage(params)
return data
}
const MemberSystem: React.FC<{}> = () => {
const ref = useRef<any>({})
const deleteItem = async (record) => {
// 删除该项
await PublicApi.postMemberRoleDelete({
memberRoleId: record.id
})
ref.current.reload()
}
const updateItem = (record) => {
history.push(`/authorityManage/roleManage/addRole?id=${record.id}&preview=0`)
}
const handleStatus = async (record) => {
await PublicApi.postMemberRoleUpdatestatus({
id: record.id,
status: record.status === 1 ? 0 : 1
})
ref.current.reload()
}
const columns: ColumnType<any>[] = [
{
title: 'ID',
dataIndex: 'id',
align: 'center',
key: 'id',
},
{
title: '角色名称',
dataIndex: 'roleName',
align: 'center',
key: 'roleName',
className: 'commonPickColor',
render: (text, record) => <EyePreview url={`/authConfig/memberSystem/memberDetail?id=${record.id}&preview=1`}>{text}</EyePreview>
},
{
title: '描述',
align: 'center',
dataIndex: 'remark',
key: 'remark',
},
{
title: '状态',
align: 'center',
dataIndex: 'status',
key: 'status',
render: (text: any, record:any) => <StatusSwitch record={record} handleConfirm={() => handleStatus(record)}/>
},
{
title: '操作',
dataIndex: 'option',
align: 'center',
render: (text:any, record:any) => {
return (
<>
<Popconfirm
title="确定要执行这个操作?"
onConfirm={() => deleteItem(record)}
okText="是"
cancelText="否"
>
<Button type='link'>删除</Button>
</Popconfirm>
<Button type='link' onClick={()=>updateItem(record)}>修改</Button>
</>
)
}
}
];
return (<div className="common-wrapper">
<StandardTable
columns={columns}
currentRef={ref}
fetchTableData={(params:any) => fetchData(params)}
formilyLayouts={{
justify: 'space-between'
}}
formilyChilds={{
layouts: {
order: 2
},
children: <Button style={{width: 140}} icon={<PlusOutlined/>} onClick={() => history.push('/authorityManage/roleManage/addRole')} type='primary'>新建</Button>
}}
formilyProps={{
layouts: {
order: 3
},
ctx: {
schema: {
type: 'object',
properties: {
name: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
}
}
}
}
}
}}
/>
</div>
)
}
export default MemberSystem
import React, { useContext, useState, useEffect, useRef, useLayoutEffect, useCallback } from 'react';
import { Row, Col, Button, Form, Input, Space, Tabs, message, Badge } from 'antd';
import {IntegrateTree} from 'god'
import PageHeader from '@/layouts/components/PageHeader';
import { history } from 'umi';
import { historyContainer } from '@/hooks/useHistoryContainer';
import NiceForm from '@/components/NiceForm';
import TabTree, { useTreeActions, createTreeActions } from '@/components/TabTree';
import { PublicApi } from '@/services/api';
import styled from './index.less'
import CheckboxTree from '@/components/CheckBoxTree';
import { useTreeTabs } from '@/hooks/useTreeTabs';
import { createFormActions } from '@formily/antd';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
// import { UserOutlined } from '@ant-design/icons';
const { TextArea } = Input;
const pageTitles = [
'新增',
'编辑',
'预览'
]
const layout = {
labelCol: {
span: 24,
},
wrapperCol: {
span: 24,
},
};
const TabFormErrors = (props) => {
return (
<Badge dot={props.dot} offset={[5,-5]}>
{props.children}
</Badge>
)
}
const fetchMenuData = async () => {
const res = await PublicApi.getMemberRoleAuthTree()
return res
}
const TabsItem = Tabs.TabPane
const menuActions = createFormActions()
const MemberDetail: React.FC<{}> = () => {
const [form] = Form.useForm();
const value = useContext(historyContainer)
const {
treeData,
handleSelect,
nodeRecord,
isEditForm,
setIsEditForm,
getTreeMaps
} = useTreeTabs({
fetchMenuData,
fetchItemDetailData: PublicApi.getMemberRoleAuthButton
})
const actionRef = useRef<any>({})
const formInitValue = nodeRecord ? getTreeMaps(nodeRecord.key) : {}
const [errors, setErrors] = useState<boolean>(false)
const [formValue, setFormValue] = useState<any>(null)
const {
pageStatus,
id
} = usePageStatus()
const treeActions = createTreeActions()
// 编辑和预览模式下需回显数据
const fetchRoleMenuDetail = async (id) => {
// 10秒缓存
const res = await PublicApi.getMemberRoleAuthTreeCheck({
memberRoleId: id
}, { useCache: true, ttl: 10 * 1000 })
return res
}
// 储存的按钮数据
const [buttonInfos, setButtonInfos] = useState<any>([])
useEffect(() => {
if (!id) return ;
fetchRoleMenuDetail(id).then(res => {
const { data } = res
setFormValue(data)
})
}, [])
useEffect(() => {
if (formInitValue) {
// 显示右侧checkbox
setButtonInfos(formInitValue.buttons || [])
// 回显右侧checkbox的值
if (actionRef.current.setSelected) {
actionRef.current.setSelected()
}
}
}, [getTreeMaps])
const handleSubmit = () => {
menuActions.submit().then(async ({values}) => {
setErrors(false)
// 如果未点击过操作权限tab, 则无法获取到actionRef实例, 需补充手动补充回显的ids, 新增的时候如果未设置按钮,则返回空数组
const buttonCheckIds = actionRef.current.selected || (formValue && formValue.ids) || []
const treeCheckIds = treeActions.getSelectKeys()
const menuIds = [...buttonCheckIds, ...treeCheckIds]
if (pageStatus === PageStatus.EDIT) {
await PublicApi.postMemberRoleUpdate({
...values,
id,
menuIds
})
} else {
await PublicApi.postMemberRoleAdd({
...values,
menuIds
})
}
history.goBack(-1)
}).catch(err => {
console.log(err)
if (Array.isArray(err)) {
setErrors(true)
}
})
}
const changeTabs = (key) => {
if (key === '2' && id) {
fetchRoleMenuDetail(id).then(res => {
const { data } = res
// 获取菜单id选中的集合
const {
checkIds,
...reset
} = data
treeActions.setSelectKeys(checkIds)
})
}
}
const extraButtons = (
<Space>
<Button type='primary' disabled={pageStatus === PageStatus.PREVIEW} onClick={handleSubmit}>保存</Button>
</Space>
)
return (
<div>
<PageHeader title={pageTitles[pageStatus]} routeInfo={{...value, hidePageHeader: false}} extra={extraButtons}/>
<div className="common-wrapper-gray">
<div className="wrapper-white">
<Tabs type='card' className='black-tabs' onChange={changeTabs}>
<TabsItem tab={<TabFormErrors dot={errors}>基本信息</TabFormErrors>} key='1'>
<NiceForm
labelCol={4}
wrapperCol={12}
initialValues={formValue}
labelAlign='left'
actions={menuActions}
editable={pageStatus !== PageStatus.PREVIEW}
previewPlaceholder=' '
schema={{
type: 'object',
properties: {
name: {
type: 'string',
title: '角色名称',
required: true
},
described: {
type: 'textarea',
title: '备注',
"x-component-props": {
rows: 4
}
},
state: {
type: 'number',
title: '状态',
"x-component": 'CustomStatus',
default: 1
}
}
}}
>
</NiceForm>
</TabsItem>
<TabsItem tab='操作权限' key='2'>
<Row justify='space-between'>
<Col span={17} className={styled['menu-role-tree']}>
<TabTree
title='菜单访问权限'
fetchData={params => fetchMenuData()}
checkable
actions={treeActions}
treeData={treeData}
handleSelect={handleSelect}
disabled={pageStatus === PageStatus.PREVIEW}
/>
</Col>
<Col span={6} className={styled['menu-role-tree']}>
<CheckboxTree
actions={actionRef}
disabled={pageStatus === PageStatus.PREVIEW}
checkedNodes={buttonInfos}
title='菜单接口访问权限'
/>
</Col>
</Row>
</TabsItem>
</Tabs>
</div>
</div>
</div>
)
}
export default MemberDetail
import React, {useState, ReactText, useEffect} from 'react';
import { Row, Col, Tree, Form, Table, InputNumber, Popconfirm, Button, Input, Modal } from 'antd';
import {
CarryOutOutlined,
FormOutlined,
PlusOutlined
} from '@ant-design/icons';
import TabTree, { useTreeActions } from '@/components/TabTree';
import SchemaForm, { createFormActions, LifeCycleTypes, FormEffectHooks } from '@formily/antd';
import { menuSchema } from './schema';
import { PublicApi } from '@/services/api';
import { omit } from '@/utils';
import { useMap, useBoolean } from '@umijs/hooks';
import { useTreeTabs } from '@/hooks/useTreeTabs';
// import "./index.less"
const { ON_FORM_INPUT_CHANGE } = LifeCycleTypes
const { onFieldInputChange$ } = FormEffectHooks
enum FormState {
FREE, // 空闲状态
EDIT, // 编辑状态
ADD, // 新增状态
}
const formActions = createFormActions()
const fetchMenuData = async (params?) => {
const res = await PublicApi.getMemberOrgTree()
return res
}
const Organ: React.FC<{}> = () => {
const {
treeStatus,
setTreeStatus,
treeData,
setIsEditForm,
nodeRecord,
setNodeRecord,
handleSelect,
getTreeMaps,
setTreeMaps,
resetMenu
} = useTreeTabs({
fetchMenuData: fetchMenuData,
fetchItemDetailData: PublicApi.getMemberOrgGet
})
const formInitValue = nodeRecord ? getTreeMaps(nodeRecord.key) : {}
const handleSubmitAllSetting = () => {
formActions.submit()
}
const handleDeleteMenu = (id) => {
PublicApi.postMemberOrgDelete({
id: id || nodeRecord.key
}).then(() => {
setTreeStatus(FormState.FREE)
setNodeRecord(undefined)
resetMenu()
})
}
// 保存设置提交
const handleSubmit = (value) => {
// 去掉模拟的key
const editOrAdd = nodeRecord && treeStatus === FormState.EDIT
const params = editOrAdd ? { ...value, parentId: nodeRecord.id } : {
...value,
parentId: nodeRecord ? nodeRecord.parentId : 0,
}
const fn = editOrAdd ? PublicApi.postMemberOrgUpdate : PublicApi.postMemberOrgAdd
fn(params).then(res => {
resetMenu()
setTreeStatus(FormState.FREE)
setNodeRecord(undefined)
// 保存后要将是否填写过表单设为false
setIsEditForm(false)
})
}
// 树形工具栏
const toolsRender = {
addNode(node) {
formActions.reset({ validate: false })
setTreeStatus(FormState.ADD)
},
addChildNode(node) {
setNodeRecord({
...node,
parentId: node.key
})
formActions.reset({ validate: false })
setTreeMaps(node.key, null)
setTreeStatus(FormState.ADD)
},
deleteNode(node) {
handleDeleteMenu(node.key)
}
}
return <div className="common-wrapper">
<Row gutter={[36, 36]}>
<Col span={8}>
<h3 className="commonPanelTitle mb-30">选择要编辑的项目</h3>
{
treeData && treeData.length > 0
? <TabTree
fetchData = {params => fetchMenuData(params)}
treeData={treeData}
toolsRender={toolsRender}
handleSelect={(key, node) => handleSelect(key, node)}
/>
:
<Button block type='primary' onClick={() => handleSelect()}>暂无菜单, 开始新增</Button>
}
</Col>
<Col span={16}>
{treeStatus !== FormState.FREE && <>
<h3 className="commonPanelTitle mb-30">{treeStatus === FormState.ADD ? '新增' : '编辑'}</h3>
<SchemaForm
schema={menuSchema}
value={formInitValue}
actions={formActions}
effects={($) => {
$(ON_FORM_INPUT_CHANGE).subscribe(() => {
setIsEditForm(true)
})
$('onFormReset').subscribe(() => {
console.log('mount')
})
}}
onSubmit={handleSubmit}
>
</SchemaForm>
<Button onClick={handleSubmitAllSetting} type="primary" style={{ marginTop: 32, marginBottom: 16, marginRight: 24}}>
保存设置
</Button>
<Popconfirm title="确定要删除吗?" okText="是" cancelText="否" onConfirm={handleDeleteMenu}>
<Button style={{ marginTop: 32, marginBottom: 16}}>
删除菜单
</Button>
</Popconfirm>
</>
}
</Col>
</Row>
</div>
}
export default Organ
import { ISchema } from '@formily/antd';
export const menuSchema: ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'top',
wrapperCol: 12
},
properties: {
code: {
type: 'string',
title: '组织代码',
required: true,
},
title: {
type: 'string',
title: '组织机构',
required: true
},
remark: {
type: 'textarea',
title: '描述',
"x-component-props": {
rows: 4
}
}
}
}
}
}
\ No newline at end of file
import React, { ReactNode, useRef } from 'react';
import { history, Link } from 'umi'
import { Button, Popconfirm } from 'antd';
import {
PlusCircleOutlined,
PlayCircleOutlined,
PauseCircleOutlined,
PlusOutlined,
EyeOutlined
} from '@ant-design/icons';
import {StandardTable} from 'god'
import {ColumnType} from 'antd/lib/table/interface'
import { IButtonFilter, IFormFilter } from 'god/dist/src/standard-table/TableController';
import { PublicApi } from '@/services/api';
import EyePreview from '@/components/EyePreview';
import StatusSwitch from '@/components/StatusSwitch';
const setInformation = (props:string) => {
history.push(`/authorityManage/userManage/addUser?id=${props}&preview=0`)
}
// 模拟请求
const fetchData = async (params) => {
const { data } = await PublicApi.getMemberUserPage(params)
return data
}
const UserSystem: React.FC<{}> = () => {
const ref = useRef<any>({})
const addItem = () => {
history.push('/authorityManage/userManage/addUser?preview=0')
}
const deleteItem = (record) => {
// 删除该项
PublicApi.postMemberUserDelete({
userId: record.id
}).then(() => {
ref.current.reload()
})
}
const updateItem = (record) => {
history.push(`/authorityManage/userManage/addUser?id=${record.id}&preview=0`)
}
const handleStatus = (record) => {
PublicApi.postMemberUserUpdatestatus({
userId: record.id,
status: record.status === 1 ? 0 : 1
}).then(res => {
ref.current.reload()
})
}
const columns: ColumnType<any>[] = [
{
title: '账号',
dataIndex: 'account',
align: 'center',
key: 'account',
className: 'commonPickColor',
render: (text, record) => <EyePreview url={`/authConfig/userSystem/userDetail?id=${record.id}&preview=1`}>{text}</EyePreview>
},
{
title: '用户姓名',
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: '绑定手机号码',
align: 'center',
dataIndex: 'tel',
key: 'tel',
},
{
title: '所属角色',
align: 'center',
dataIndex: 'roleNames',
key: 'roleNames',
},
{
title: '最后登录时间',
align: 'center',
dataIndex: 'updateTime',
key: 'updateTime',
},
{
title: '外部状态',
align: 'center',
dataIndex: 'state',
key: 'state',
render: (text: any, record:any) => <StatusSwitch handleConfirm={() => handleStatus(record)} record={record}/>
},
{
title: '操作',
dataIndex: 'option',
align: 'center',
render: (text:any, record:any) => {
return record.state === 0 && (
<>
<Popconfirm
title="确定要执行这个操作?"
onConfirm={() => deleteItem(record)}
okText="是"
cancelText="否"
>
<Button type='link'>删除</Button>
</Popconfirm>
<Button type='link' onClick={()=>updateItem(record)}>修改</Button>
</>
)
}
}
];
return (<div className="common-wrapper">
<StandardTable
columns={columns}
currentRef={ref}
fetchTableData={(params:any) => fetchData(params)}
formilyLayouts={{
justify: 'space-between'
}}
formilyChilds={{
layouts: {
order: 2
},
children: <Button style={{width: 140}} icon={<PlusOutlined/>} onClick={addItem} type='primary'>新建</Button>
}}
formilyProps={{
layouts: {
order: 3
},
ctx: {
schema: {
type: 'object',
properties: {
name: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
}
}
}
}
}
}}
/>
</div>
)
}
export default UserSystem
import React, { useRef, useState, useEffect } from 'react';
import { Button, Modal, Tag, Row, Col } from 'antd';
import { Form, FormItem, createFormActions } from '@formily/antd'
import { Input } from '@formily/antd-components'
import { PlusOutlined } from '@ant-design/icons';
import {StandardTable} from 'god'
import {ColumnType} from 'antd/lib/table/interface';
import { PublicApi } from '@/services/api';
import { history } from 'umi';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import DetailPage from '@/components/DetailPage';
const layout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 12,
},
};
const tailLayout = {
wrapperCol: {
offset: 6,
span: 18,
},
};
// 定义选择的行数据的类型
type Item = any
const titleRender = (title) => {
if (title === PageStatus.PREVIEW) return '查看用户'
if (title === PageStatus.ADD) return '新增用户'
if (title === PageStatus.EDIT) return '编辑用户'
return ''
}
const form = createFormActions()
const AddUser: React.FC<{}> = () => {
const checkBoxRef = useRef<any[]>([])
const [roleVisible, setRoleVisible] = useState(false)
const [selectRow, setSelectRow] = useState<Item[]>([]) // 模态框选择的行数据
const [selectedRowKeys, setSelectedRowKeys] = useState<Array<string>>([])
const ref = useRef<any>({})
const [formData, setFormData] = useState<any>(null)
const { id, pageStatus } = usePageStatus()
useEffect(() => {
if (id) {
// PublicApi.getMiddlegroundUserDetailsById({
// userId: id
// }).then(res => {
// const { data } = res
// setFormData(data)
// setSelectRow(data.roles)
// })
}
}, [])
const onFinish = async (values:any) => {
if (values.roles) {
delete values.roles
}
let value = { ...values, 'roleIds': selectRow.map(v => v.id) }
const fn = id ? PublicApi.postMemberUserUpdate : PublicApi.postMemberUserAdd
const params = id ? {
...value,
id: Number(id)
} : value
await fn(params)
history.goBack(-1)
};
const handleSelectOk = () => {
setRoleVisible(false)
setSelectRow(checkBoxRef.current)
}
const handleSelectCancel = () => {
setRoleVisible(false)
}
// 模拟请求
const fetchData = async (params:any) => {
const data = await PublicApi.getMemberOrgTree(params)
return data.data
}
const columns: ColumnType<any>[] = [
{
title: '角色ID',
dataIndex: 'id',
align: 'center',
key: 'id',
},
{
title: '角色名称',
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: '描述',
align: 'center',
dataIndex: 'described',
key: 'described',
}
]
console.log(selectedRowKeys)
const rowSelection = {
selectedRowKeys: selectedRowKeys,
onChange: (selectedRowKeys: any, selectedRows: any) => {
checkBoxRef.current = selectedRows
setSelectedRowKeys(selectedRowKeys);
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
}
};
const handleCloseTag = (removedTag: any) => {
const selectRows = selectRow.filter((tag:any) => tag.id !== removedTag.id);
setSelectRow(selectRows);
console.log(selectRows, 'selectRows');
};
const handleAddRole = () => {
setRoleVisible(true);
setSelectedRowKeys(selectRow.map(v => v.id))
checkBoxRef.current = selectRow
}
useEffect(()=>{
console.log(selectRow,'change')
}, [selectRow])
return (
<DetailPage title={titleRender(pageStatus)}>
<div className="common-wrapper">
<Form {...layout} actions={form} initialValues={formData} editable={pageStatus !== PageStatus.PREVIEW} name="control-hooks" onSubmit={onFinish} >
<FormItem
name="account"
label="登录账号"
component={Input}
rules={[
{
required: true,
message: '登录账号为必填!'
},
]}
/>
<FormItem
name="password"
label="初始密码"
component={Input}
rules={[
{
required: true,
message: '初始密码为必填!'
},
]}
/>
<FormItem
name="name"
label="用户姓名"
rules={[
{
required: true,
message: '用户姓名为必填!'
},
]}
component={Input}
/>
<FormItem
name="tel"
label="手机号码"
rules={[
{
required: true,
message: '手机号码为必填!'
},
]}
component={Input}
/>
<FormItem
name="identityCard"
label="身份证号码"
component={Input}
/>
<FormItem
name="email"
label="Email"
component={Input}
/>
<FormItem
name="post"
label="职位"
component={Input}
/>
<FormItem
name="roleIds"
label="关联角色"
>
<>
{
selectRow.length>0 && selectRow.map((tag, index) => {
return (
<Tag
style={{marginBottom:12}}
color="cyan"
className="edit-tag"
key={index}
closable={pageStatus !== PageStatus.PREVIEW}
onClose={() => handleCloseTag(tag)}
>
{tag.name}
</Tag>
);
})
}
{ pageStatus !== PageStatus.PREVIEW && <Button onClick={handleAddRole} style={{width:'100%'}} icon={<PlusOutlined />}>添加角色</Button> }
</>
</FormItem>
<Row>
{
pageStatus !== PageStatus.PREVIEW
&&
<Col {...tailLayout.wrapperCol}>
<Button type="primary" onClick={() => form.submit()}>
提交
</Button>
<Button className="ml-20">
取消
</Button>
</Col>
}
</Row>
</Form>
<Modal
title="选择角色"
visible={roleVisible}
onOk={handleSelectOk}
onCancel={handleSelectCancel}
okText="确认"
cancelText="取消"
>
<StandardTable
columns={columns}
currentRef={ref}
rowSelection={rowSelection}
fetchTableData={(params:any) => fetchData(params)}
tableProps={{ rowKey: 'id' }}
formilyProps={{
layouts: {
order: 3
},
ctx: {
schema: {
type: 'object',
properties: {
name: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
}
}
}
}
}
}
}
/>
</Modal>
</div>
</DetailPage>
);
};
export default AddUser
import { isDev } from '@/constants'
export interface AuthInfo {
userId: number,
memberId: number,
......@@ -12,7 +10,7 @@ export const setAuth = (info: AuthInfo) => {
export const getAuth = () => {
try {
return JSON.parse(window.localStorage.getItem('auth')) || null
return JSON.parse(window.localStorage.getItem('auth') || '') || null
} catch (error) {
return {}
}
......@@ -25,11 +23,7 @@ export const setRouters = (routers: any[]) => {
export const getRouters = () => {
try {
return JSON.parse(window.sessionStorage.getItem('rt')).concat([
'/memberCenter/commodityAbility',
'/memberCenter/commodityAbility/classAndProperty',
'/memberCenter/commodityAbility/classAndProperty/attribute'
]) || []
return JSON.parse(window.sessionStorage.getItem('rt') || '') || []
} catch (error) {
return []
}
......
......@@ -135,6 +135,17 @@ export const getAsyncSelectList = async (asyncList: any[]) => {
}
}
// 抽离对象中的某些属性, 并返回一个新对象
export const omit = (obj: any, arr: string[]): any => {
const newObj = deepClone(obj)
for(let item = 0; item < arr.length; item++) {
if (obj[arr[item]] !== undefined) {
delete newObj[arr[item]]
}
}
return newObj
}
export const findItemAndDelete = (arr: any[], target) => {
const newArr = [...arr]
if (newArr.length > 0 && isObject(newArr[0])) {
......@@ -163,6 +174,28 @@ export const findTreeKeys = (arr: any[], keyword?: string) => {
return results
}
// 数组通过某个key进行去重合并, 并返回一个新数组
export const mergeArrByKey = (preArr: any[], nextArr: any[], target?: string) => {
const mergeArr = preArr.concat(nextArr)
if (target) {
const result: any[] = []
mergeArr.forEach(v => {
const s = result.find(j => j[target] === v[target])
if (!s) {
result.push(v)
}
})
return result
} else {
return Array.from(new Set(mergeArr))
}
}
// 数组去重
export const dupliArr = (arr: any[]) => {
return Array.from(new Set(arr))
}
export default {
isArray,
isObject,
......
......@@ -4,6 +4,7 @@ import { IRequestError, IRequestSuccess } from '..';
import { history } from 'umi'
import { message } from 'antd'
import { getAuth, removeAuth } from './auth';
import { isDev } from '@/constants';
export type CtlType = 'none' | 'message'
// 根前缀请求路径
......@@ -104,8 +105,12 @@ class ApiRequest {
baseRequest<IRequestSuccess<T>>(url, options).then(res => {
// 登录验证
if (res.code === 1101) {
if (isDev) {
return ;
}
removeAuth()
history.replace('/user/login')
history.replace('/login')
message.error(res.message)
return false
}
......@@ -114,11 +119,6 @@ class ApiRequest {
options.ctlType === 'message' && message.success(res.message)
resolve(res)
} else {
// 未登录
if (res.code === 1101) {
history.push('/user/login')
reject()
}
message.error(res.message)
}
......
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