Commit 22e211af authored by 前端-钟卫鹏's avatar 前端-钟卫鹏
parents 929f4801 56ecb93c
......@@ -127,29 +127,7 @@ const router = [
component: '@/pages/member/memberLevel/addEquity',
},
],
},
{
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',
},
],
},
}
],
},
];
......
......@@ -17,6 +17,8 @@ export default {
path: '/authConfig/memberSystem/memberDetail',
name: 'memberDetail',
component: '@/pages/authConfig/memberSystem/memberDetail',
hideInMenu: true,
hidePageHeader: true
},
{
path: '/authConfig/userSystem',
......@@ -27,6 +29,8 @@ export default {
path: '/authConfig/userSystem/userDetail',
name: 'userSystem',
component: '@/pages/authConfig/userSystem/userDetail',
hideInMenu: true,
hidePageHeader: true
},
],
}
\ No newline at end of file
const MAIN_COLOR = '#00B37A'
const MAIN_FONT_BOLD_COLOR = '#172B4D'
const MAIN_FONT_TINY_COLOR = '#6B778C'
/**
* 定制antd主题样式
......@@ -7,6 +9,12 @@ const MAIN_COLOR = '#00B37A'
export default {
"layout-header-background": "#38414A",
'primary-color': MAIN_COLOR,
// tabs
'tabs-card-active-color': MAIN_FONT_BOLD_COLOR,
'tabs-highlight-color': MAIN_FONT_BOLD_COLOR,
'tabs-hover-color': MAIN_FONT_BOLD_COLOR,
'tabs-active-color': MAIN_FONT_BOLD_COLOR,
'tabs-card-head-background': '#fff',
// 'link-color': MAIN_COLOR,
// 'link-hover-color': MAIN_COLOR,
// 'link-active-color': MAIN_COLOR,
......
......@@ -4,8 +4,10 @@
"api": "god-ytt",
"start:analyze": "ANALYZE=1 umi dev",
"scripts:build": "node scripts/run",
"scripts:build-yxc": "node scripts/run http://yxc-web-demo.shushangyun.com/api",
"start": "yarn api && yarn scripts:build && umi dev",
"build": "yarn api && yarn scripts:build && umi build",
"build:yxc": "yarn api && yarn scripts:build-yxc && umi build",
"build:dev": "pm2 start scripts/devServer.js",
"build:analyze": "ANALYZE=1 umi build",
"postinstall": "umi generate tmp",
......@@ -34,7 +36,7 @@
"braft-editor": "^2.3.9",
"classnames": "^2.2.6",
"core-js": "^3.6.5",
"god": "^0.1.18",
"god": "0.1.20",
"lint-staged": "^10.0.7",
"mobx": "^5.15.4",
"mobx-react": "^6.2.2",
......@@ -50,8 +52,9 @@
"express": "^4.17.1",
"god-yapi2ts": "^1.6.0",
"gulp": "^4.0.2",
"http-proxy-middleware": "^1.0.5",
"json2ts": "^0.0.7",
"ora": "^4.0.4",
"http-proxy-middleware": "^1.0.5"
"typescript": "^3.9.7"
}
}
......@@ -17,8 +17,10 @@ const demoFetch = require('../../demo').fetchConfig
const isDemo = true
const remoteUrl = process.argv[2] || 'http://10.0.0.25:8100'
const axios = Axios.create({
baseURL: 'http://10.0.0.25:8100',
baseURL: remoteUrl,
responseType: 'json',
})
......@@ -33,8 +35,6 @@ const serviceConfig = {
url: '/member/menu/register/detail',
method: 'get'
},
},
//初始化会员支付策略配置
payConfig:{
......@@ -55,8 +55,13 @@ async function batchAxiosHttps() {
for (const item in serviceConfig) {
if(JSON.stringify(item) !== '{}'){
for (const subItem in serviceConfig[item]) {
try {
const data = await axios(serviceConfig[item][subItem])
asyncHttpQueue[item][subItem] = data.data.data
} catch(err) {
console.log(serviceConfig[item][subItem].url)
console.log(err.response.data)
}
}
}
......
.common_detail_page {
margin: -24px;
// margin: -24px;
.common_header {
display: flex;
......
import React, { ReactText, useRef, useEffect } from 'react'
import {StandardTable} from 'god'
import { IStandardTableProps } from 'god/dist/src/standard-table'
import { Row, Col, Modal } from 'antd'
export interface ModalTableProps extends IStandardTableProps<any> {
width?: number,
modalTitle?: ReactText,
confirm?(),
cancel?(),
visible?: boolean
}
const ModalTable:React.FC<ModalTableProps> = (props) => {
const { width = 704,modalTitle, confirm, cancel, visible, currentRef, ...resetTable } = props
const selfRef = currentRef || useRef<any>({})
useEffect(() => {
if (!visible) {
selfRef.current.resetField && selfRef.current.resetField({
validate: false
})
}
}, [visible, selfRef.current])
return (
<Modal
width={width}
title={modalTitle}
onOk={confirm}
onCancel={cancel}
visible={visible}
>
<StandardTable
tableType='small'
currentRef={selfRef}
formRender={(child, ps) => <Row justify='space-between'>
<Col>{child}</Col>
<Col style={{marginTop: 4}}>{ps}</Col>
</Row>}
{...resetTable}
>
</StandardTable>
</Modal>
)
}
ModalTable.defaultProps = {}
export default ModalTable
\ No newline at end of file
import React, { useState } from 'react'
import { Tag, Row } from 'antd'
import { useFormEffects } from '@formily/antd'
const TableTagList = (props) => {
const { value = [], mutators } = props
const { extra = null, callback = null } = props.props['x-component-props'] ? props.props['x-component-props'] : {}
const handleClose = (id) => {
callback && callback(id)
mutators.remove(value.findIndex(v => v.id === id))
}
return (
<div className="table-tag-list" style={{width: '100%'}}>
<Row style={{flexWrap: 'wrap'}}>
{
value.map(v => <Tag closable onClose={() => handleClose(v.id)} color="#4279DF" key={v.id} style={{marginBottom: 8}}>{v.roleName}</Tag>)
}
</Row>
{extra}
</div>
)
}
TableTagList.defaultProps = {}
TableTagList.isFieldComponent = true;
export default TableTagList
\ No newline at end of file
......@@ -24,3 +24,26 @@
border-bottom: 1px solid #DFE1E6;
}
}
.flex-layout-label-required {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 32px;
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
&::before {
display: inline-block;
margin-right: 4px;
color: #ff4d4f;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
content: '*';
}
}
\ No newline at end of file
import React from 'react';
import SchemaForm, {
IAntdSchemaFormProps, createVirtualBox, registerVirtualBox, Schema, SchemaField, FormButtonGroup, Reset, createControllerBox,
IAntdSchemaFormProps, createVirtualBox, registerVirtualBox, Schema, SchemaField, FormButtonGroup, Reset, createControllerBox, FormItem,
} from '@formily/antd';
import { Button, Space, Row, Col } from 'antd';
import styled from 'styled-components'
......@@ -17,9 +17,9 @@ import CustomRegistryPhone from './components/CustomRegistryPhone';
import CustomRelevance from './components/CustomRelevance';
import Children from './components/Children';
import CircleBox from './components/CircleBox';
import TableTagList from './components/TableTagList';
import './index.less'
import { Input } from '@formily/antd-components';
import cx from 'classnames'
export interface NiceFormProps extends IAntdSchemaFormProps {}
const RowLayout = styled(props => <Row justify='end' {...props}/>)`
......@@ -74,6 +74,28 @@ const schemaLayout = createControllerBox("schemaLayout", (_props) => {
</NiceForm>
);
});
const renderCol = (schema, isLast) => {
const { flexcol = {} } = schema['x-component-props']
return <Col style={isLast ? {} : {marginRight: 24}} {...flexcol} key={schema.path}>
<SchemaField schema={schema.toJSON()} path={schema.path}/>
</Col>
}
registerVirtualBox('flex-box', props => {
const childProperties = props.schema.getOrderProperties()
const { title, required } = props.props
const {labelcol, wrappercol} = props.schema.getExtendsComponentProps()
return <Row>
{ title && <Col span={labelcol} className={cx(required ? 'flex-layout-label-required' : '')}>{title}</Col>}
<Col span={wrappercol}>
<Row>
{
childProperties.map((v, i, arr) => renderCol(v.schema, arr.length - 1 === i))
}
</Row>
</Col>
</Row>
})
const NiceForm: React.FC<NiceFormProps> = props => {
const { children, components, ...reset } = props;
const customComponents = {
......@@ -91,7 +113,8 @@ const NiceForm: React.FC<NiceFormProps> = props => {
Children,
CircleBox,
SchemaFormButtonGroup,
FlexBox
FlexBox,
TableTagList
};
const defineComponents = Object.assign(customComponents, components);
......
import React, { useState, ReactText, useImperativeHandle, useEffect, useRef } from 'react'
import { Tree, Space, Tooltip, Button } from 'antd'
import { findItemAndDelete, findTreeKeys } from '@/utils'
import { findItemAndDelete, findTreeKeys, treeReduction, getParentTreeTitles } from '@/utils'
import './index.less'
import deepClone from 'clone'
import { TreeProps } from 'antd/lib/tree'
......@@ -17,6 +17,7 @@ export interface TabTreeActions {
setExpandedKeys: (keys: ReactText[]) => void,
setSelectKey: (key: ReactText) => void
setSelectKeys: (keys: ReactText[]) => void
getParentPath: (id: ReactText) => string
}
export interface toolsRenderProps {
......@@ -63,6 +64,7 @@ export const createTreeActions = () => {
setSelectKey(){},
setSelectKeys(){},
setExpandedKeys(){},
getParentPath(id){return ''},
}
return actions
}
......@@ -163,6 +165,8 @@ const TabTree:React.FC<TabTreeProps> = (props) => {
checkedKeys,
[]
);
console.log(treeReduction(treeData))
useEffect(() => {
if (getMenuSelectData) {
getMenuSelectData().then(res => {
......@@ -193,6 +197,10 @@ const TabTree:React.FC<TabTreeProps> = (props) => {
selfActions.setSelectKey = (key: ReactText) => {
setSelectKey(key)
}
selfActions.getParentPath = (id: ReactText) => {
return getParentTreeTitles(treeData, id)
}
}
const batchSelect = (items: any[]) => {
......@@ -224,6 +232,7 @@ const TabTree:React.FC<TabTreeProps> = (props) => {
const { node, selected } = e
// 用户自定义的选择后触发事件
if (props.handleSelect) {
console.log(node)
const result = props.handleSelect(node.key, node)
// 存在返回值则不执行选中事件, 一般用于切换node时,不希望离开当前页面
if (result !== undefined) {
......
/*
* @Author: LeeJiancong
* @Date: 2020-07-22 09:54:50
* @LastEditors: LeeJiancong
* @LastEditTime: 2020-07-30 19:28:23
*/
/**
* 正则表达式集合
*/
export const PATTERN_MAPS = {
// 8-20位, 大小写字幕 + 数字组合
password: /^(?=.*[a-z])(?=.*[A-Z])[a-zA-Z\d]{8,20}$/,
email: /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/,
phone: /^1[3|4|5|6|7|8|9][0-9]{9}$/,
smsCode: /^\d{6}$/,
money:/^\d*(?:\.\d{0,2})?$/,
weight:/^\d*(?:\.\d{0,3})?$/,
}
\ No newline at end of file
......@@ -15,12 +15,33 @@ body,
min-height: 100vh !important;
}
.wrapper-white {
background: #fff;
border-radius: 8px;
padding: 24px;
}
.connectBtn {
width: 80px;
height: 32px;
line-height: 32px;
background: #6B778C;
color: #fff;
text-align: center;
cursor: pointer;
}
// 内嵌页公共wrapper
.common-wrapper {
background-color: #fff;
padding: 32px 24px;
border-radius: 5px;
}
.common-wrapper-gray {
background-color: #F5F6FA;
padding: 32px 24px;
border-radius: 5px;
}
// 公共显示隐藏处理
.commonShowBlock {
......
......@@ -23,7 +23,7 @@ export function useHttpRequest<T>(api: (params?, config?) => Promise<T>, config?
setLoading(true)
api(params).then((res: any) => {
setData(res.data)
if (config && config.back) {
if (res.code === 1000 && config && config.back) {
setTimeout(() => {
goBack()
}, 1000)
......
......@@ -54,6 +54,12 @@ export const useRowSelectionTable = (options: useRowSelectionOptions = {}): [Tab
type,
// 为解决分页情况下, 保存多选的数据
onSelect: (record, selects, selectedRows, nativeEvent) => {
if (type === 'radio') {
// 单选情况下
setSelectedRowKeys([record.id])
setSelectRow([record])
return ;
}
const findIds = selectedRowKeys.indexOf(record.id)
if (findIds === -1) {
mergeRowKeys(record.id)
......
......@@ -38,6 +38,8 @@
}
.lx-page-header {
display: flex;
justify-content: space-between;
background: #fff;
padding: 0 24px;
height: 64px;
......@@ -52,6 +54,7 @@
min-height: calc(100vh - 200px);
&.noHeader {
padding: 0;
min-height: calc(100vh - 156px);
}
}
......
......@@ -52,6 +52,7 @@ export default {
'menu.authConfig': '平台权限',
'menu.authConfig.organ': '组织机构',
'menu.authConfig.memberSystem': '角色管理',
'menu.authConfig.memberDetail': '角色详情',
'menu.authConfig.userSystem': '用户管理',
// 会员能力
'menu.memberAbility': '会员管理',
......
......@@ -32,7 +32,7 @@ const MemberSystem: React.FC<{}> = () => {
}
const updateItem = (record) => {
history.push(`/authorityManage/roleManage/addRole?id=${record.id}&preview=0`)
history.push(`/authConfig/memberSystem/memberDetail?id=${record.id}&preview=0`)
}
const handleStatus = async (record) => {
......@@ -94,7 +94,7 @@ const MemberSystem: React.FC<{}> = () => {
}
];
return (<div className="common-wrapper">
return (<div className="common-wrapper-gray">
<StandardTable
columns={columns}
currentRef={ref}
......@@ -106,7 +106,7 @@ const MemberSystem: React.FC<{}> = () => {
layouts: {
order: 2
},
children: <Button style={{width: 140}} icon={<PlusOutlined/>} onClick={() => history.push('/authorityManage/roleManage/addRole')} type='primary'>新建</Button>
children: <Button style={{width: 140}} icon={<PlusOutlined/>} onClick={() => history.push('/authConfig/memberSystem/memberDetail')} type='primary'>新建</Button>
}}
formilyProps={{
layouts: {
......@@ -116,7 +116,7 @@ const MemberSystem: React.FC<{}> = () => {
schema: {
type: 'object',
properties: {
name: {
roleName: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
......
......@@ -12,22 +12,12 @@ 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 (
......@@ -76,7 +66,7 @@ const MemberDetail: React.FC<{}> = () => {
// 编辑和预览模式下需回显数据
const fetchRoleMenuDetail = async (id) => {
// 10秒缓存
const res = await PublicApi.getMemberRoleAuthTreeCheck({
const res = await PublicApi.getMemberRoleGet({
memberRoleId: id
}, { useCache: true, ttl: 10 * 1000 })
return res
......@@ -171,12 +161,12 @@ const MemberDetail: React.FC<{}> = () => {
schema={{
type: 'object',
properties: {
name: {
roleName: {
type: 'string',
title: '角色名称',
required: true
},
described: {
remark: {
type: 'textarea',
title: '备注',
"x-component-props": {
......
......@@ -12,6 +12,7 @@ import { PublicApi } from '@/services/api';
import { omit } from '@/utils';
import { useMap, useBoolean } from '@umijs/hooks';
import { useTreeTabs } from '@/hooks/useTreeTabs';
import { isObject } from '@antv/util';
// import "./index.less"
const { ON_FORM_INPUT_CHANGE } = LifeCycleTypes
......@@ -56,7 +57,7 @@ const Organ: React.FC<{}> = () => {
const handleDeleteMenu = (id) => {
PublicApi.postMemberOrgDelete({
id: id || nodeRecord.key
id: isObject(id) ? nodeRecord.key : id
}).then(() => {
setTreeStatus(FormState.FREE)
setNodeRecord(undefined)
......@@ -66,7 +67,7 @@ const Organ: React.FC<{}> = () => {
// 保存设置提交
const handleSubmit = (value) => {
// 去掉模拟的key
// 去掉模拟的key, 为true的时候是编辑
const editOrAdd = nodeRecord && treeStatus === FormState.EDIT
const params = editOrAdd ? { ...value, parentId: nodeRecord.id } : {
...value,
......@@ -86,6 +87,7 @@ const Organ: React.FC<{}> = () => {
const toolsRender = {
addNode(node) {
formActions.reset({ validate: false })
setNodeRecord(undefined)
setTreeStatus(FormState.ADD)
},
addChildNode(node) {
......@@ -112,6 +114,7 @@ const Organ: React.FC<{}> = () => {
fetchData = {params => fetchMenuData(params)}
treeData={treeData}
toolsRender={toolsRender}
customKey='id'
handleSelect={(key, node) => handleSelect(key, node)}
/>
:
......
.user-system {
.ant-input-group-addon {
padding: 0;
border: none;
}
}
......@@ -15,10 +15,6 @@ 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)
......@@ -29,24 +25,24 @@ const UserSystem: React.FC<{}> = () => {
const ref = useRef<any>({})
const addItem = () => {
history.push('/authorityManage/userManage/addUser?preview=0')
history.push('/authConfig/userSystem/userDetail?preview=0')
}
const deleteItem = (record) => {
// 删除该项
PublicApi.postMemberUserDelete({
userId: record.id
userId: record.userId
}).then(() => {
ref.current.reload()
})
}
const updateItem = (record) => {
history.push(`/authorityManage/userManage/addUser?id=${record.id}&preview=0`)
history.push(`/authConfig/userSystem/userDetail?id=${record.userId}&preview=0`)
}
const handleStatus = (record) => {
PublicApi.postMemberUserUpdatestatus({
userId: record.id,
userId: record.userId,
status: record.status === 1 ? 0 : 1
}).then(res => {
ref.current.reload()
......@@ -59,7 +55,7 @@ const UserSystem: React.FC<{}> = () => {
align: 'center',
key: 'account',
className: 'commonPickColor',
render: (text, record) => <EyePreview url={`/authConfig/userSystem/userDetail?id=${record.id}&preview=1`}>{text}</EyePreview>
render: (text, record) => <EyePreview url={`/authConfig/userSystem/userDetail?id=${record.userId}&preview=1`}>{text}</EyePreview>
},
{
title: '用户姓名',
......@@ -71,26 +67,26 @@ const UserSystem: React.FC<{}> = () => {
{
title: '绑定手机号码',
align: 'center',
dataIndex: 'tel',
key: 'tel',
dataIndex: 'phone',
key: 'phone',
},
{
title: '所属角色',
align: 'center',
dataIndex: 'roleNames',
key: 'roleNames',
dataIndex: 'roleName',
key: 'roleName',
},
{
title: '最后登录时间',
align: 'center',
dataIndex: 'updateTime',
key: 'updateTime',
dataIndex: 'lastLoginTime',
key: 'lastLoginTime',
},
{
title: '外部状态',
align: 'center',
dataIndex: 'state',
key: 'state',
dataIndex: 'status',
key: 'status',
render: (text: any, record:any) => <StatusSwitch handleConfirm={() => handleStatus(record)} record={record}/>
},
{
......@@ -98,7 +94,7 @@ const UserSystem: React.FC<{}> = () => {
dataIndex: 'option',
align: 'center',
render: (text:any, record:any) => {
return record.state === 0 && (
return record.status === 0 && (
<>
<Popconfirm
title="确定要执行这个操作?"
......
import { ISchema } from '@formily/antd';
import { PATTERN_MAPS } from '@/constants/regExp';
export const UserDetailSchema:ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 6,
labelAlign: 'left',
full: true,
wrapperCol: 12
},
properties: {
account: {
type: 'string',
title: '登录账号',
required: true
},
password: {
type: 'password',
title: '登录密码',
"x-rules": [
{
pattern: PATTERN_MAPS.password,
message: '请输入由大小写字母和数字组成的8位密码'
}
],
required: true
},
name: {
type: 'string',
title: '姓名',
required: true
},
phoneLayout: {
type: 'object',
"x-component": 'flex-box',
title: '手机号',
"x-component-props": {
labelcol: 6,
wrappercol: 12
},
required: true,
properties: {
countryCode: {
required: true,
type: 'string',
enum: ['+86'],
"x-mega-props": {
wrapperCol: 24
},
"x-component-props": {
flexcol: {
span: 6
}
}
},
phone: {
type: 'number',
required: true,
"x-mega-props": {
wrapperCol: 24,
full: true
},
"x-rules": [
{
pattern: PATTERN_MAPS.phone,
message: '请输入正确的手机号'
}
],
"x-component-props": {
flexcol: {
flex: 1
}
}
}
}
},
idCardNo: {
type: 'string',
title: '身份证号'
},
email: {
type: 'string',
title: '邮箱',
"x-rules": [
{
pattern: PATTERN_MAPS.email,
message: '请输入正确的邮箱'
}
]
},
jobTitle: {
type: 'string',
title: '职位'
},
orgName: {
type: 'string',
title: '所属组织机构',
required: true,
'x-component-props': {
disabled: true,
addonAfter: "{{connectCategory}}"
},
},
orgId: {
type: 'string',
visible: false
},
memberRoleIds: {
required: true,
type: 'array:string',
"x-component": 'tableTagList',
"x-component-props": {
extra: "{{addRoles}}",
callback: "{{callback}}"
},
title: '关联角色'
},
}
}
}
}
\ No newline at end of file
import React, { useRef, useState, useEffect } from 'react';
import { Button, Modal, Tag, Row, Col } from 'antd';
import { Form, FormItem, createFormActions } from '@formily/antd'
import { Form, FormItem, createFormActions, FormButtonGroup, Submit } from '@formily/antd'
import { Input } from '@formily/antd-components'
import { PlusOutlined } from '@ant-design/icons';
import { PlusOutlined, LinkOutlined } 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';
import NiceForm from '@/components/NiceForm';
import { UserDetailSchema } from './schema';
import './index.less'
import ModalTable from '@/components/ModalTable';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import { findItemAndDelete, omit, getParentTreeTitles } from '@/utils';
import TabTree, { useTreeActions } from '@/components/TabTree';
import { useTreeTabs } from '@/hooks/useTreeTabs';
import { useHttpRequest } from '@/hooks/useHttpRequest';
const layout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 12,
},
};
const tailLayout = {
wrapperCol: {
offset: 6,
span: 18,
},
};
// 定义选择的行数据的类型
type Item = any
......@@ -34,52 +29,80 @@ const titleRender = (title) => {
return ''
}
const form = createFormActions()
const fetchOriginTreeData = async (params?) => { // 平台后台树
const res = await PublicApi.getMemberOrgTree({}, { ttl: 10, useCache: true })
return res
}
const userActions = createFormActions()
const AddUser: React.FC<{}> = () => {
const [originVisible, setOriginVisible] = useState(false)
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()
const [roleSelection, roleSelectCtl] = useRowSelectionTable()
const originTreeActions = useTreeActions()
const [originSelectNode, setOriginSelectNode] = useState<any>()
const { data, loading, err, run } = useHttpRequest(id ? PublicApi.postMemberUserUpdate : PublicApi.postMemberUserAdd)
const {
treeData: originTreeData,
} = useTreeTabs({
fetchMenuData: fetchOriginTreeData,
})
useEffect(() => {
if (id) {
// PublicApi.getMiddlegroundUserDetailsById({
// userId: id
// }).then(res => {
// const { data } = res
// setFormData(data)
// setSelectRow(data.roles)
// })
PublicApi.getMemberUserGet({
userId: id
}).then(async res => {
const { data } = res
fetchOriginTreeData().then(({data: dataSource}) => {
setFormData({...data, orgName: getParentTreeTitles(dataSource, data.orgId), memberRoleIds: data.memberRoleIds.map((v,i) => {
return {
id: v,
roleName: data.memberRoleNames[i]
}
})})
})
})
}
}, [])
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
values.memberRoleIds = values.memberRoleIds.map(v => v.id)
const omitValue = omit(values, ['orgName'])
const params = id ? {
...value,
id: Number(id)
} : value
await fn(params)
...omitValue,
userId: Number(id)
} : omitValue
await run(params)
setTimeout(() => {
history.goBack(-1)
}, 300)
};
const handleSelectOk = () => {
// 角色确认弹窗
const roleConfirm = () => {
setRoleVisible(false)
setSelectRow(checkBoxRef.current)
userActions.setFieldValue('memberRoleIds', roleSelectCtl.selectRow)
}
const handleSelectCancel = () => {
setRoleVisible(false)
}
const handleRoleBtn = () => {
setRoleVisible(true)
const selectRoles = userActions.getFieldValue('memberRoleIds')
roleSelectCtl.setSelectRow(selectRoles)
roleSelectCtl.setSelectedRowKeys(selectRoles.map(v => v.id))
}
// 模拟请求
const fetchData = async (params:any) => {
const data = await PublicApi.getMemberOrgTree(params)
const fetchUserList = async (params:any) => {
const data = await PublicApi.getMemberRolePage(params)
return data.data
}
......@@ -92,159 +115,80 @@ const AddUser: React.FC<{}> = () => {
},
{
title: '角色名称',
dataIndex: 'name',
dataIndex: 'roleName',
align: 'center',
key: 'name',
key: 'roleName',
},
{
title: '描述',
align: 'center',
dataIndex: 'described',
key: 'described',
dataIndex: 'remark',
key: 'remark',
}
]
console.log(selectedRowKeys)
const rowSelection = {
selectedRowKeys: selectedRowKeys,
onChange: (selectedRowKeys: any, selectedRows: any) => {
checkBoxRef.current = selectedRows
setSelectedRowKeys(selectedRowKeys);
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
const handleOrigin = () => {
setOriginVisible(false)
if(originSelectNode?.id){
userActions.setFieldValue('orgName', originTreeActions.getParentPath(originSelectNode.id))
userActions.setFieldValue('orgId', originSelectNode.id)
}
}
};
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])
const handlePlateformSelect = (key, node) => {
setOriginSelectNode({id: key*1, name: node._title})
}
const openOriginTree = () => {
setOriginVisible(true)
}
const connectCategory = <div className='connectBtn' onClick={openOriginTree}><LinkOutlined style={{marginRight: 4}}/>关联</div>
const addRoles = <Button block onClick={handleRoleBtn}>添加角色</Button>
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>
);
<div className="common-wrapper user-system">
<NiceForm
onSubmit={onFinish}
schema={UserDetailSchema}
initialValues={formData}
actions={userActions}
effects={($, {setFieldState}) => {
$('onFormInit').subscribe(() => {
if (id) {
setFieldState('password', state => {
state.visible = false
})
}
{ 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="取消"
})
}}
expressionScope={{
connectCategory,
addRoles,
callback: (id) => {
roleSelectCtl.setSelectRow(findItemAndDelete(roleSelectCtl.selectRow, id))
roleSelectCtl.setSelectedRowKeys(findItemAndDelete(roleSelectCtl.selectedRowKeys, id))
}
}}
>
<StandardTable
<FormButtonGroup offset={6}>
<Button htmlType='submit' type='primary' loading={loading}>提交</Button>
<Button>取消</Button>
</FormButtonGroup>
</NiceForm>
<ModalTable
modalTitle='选择角色'
visible={roleVisible}
confirm={roleConfirm}
cancel={handleSelectCancel}
columns={columns}
rowSelection={roleSelection}
currentRef={ref}
rowSelection={rowSelection}
fetchTableData={(params:any) => fetchData(params)}
fetchTableData={(params:any) => fetchUserList(params)}
tableProps={{ rowKey: 'id' }}
formilyProps={{
layouts: {
......@@ -254,7 +198,7 @@ const AddUser: React.FC<{}> = () => {
schema: {
type: 'object',
properties: {
name: {
roleName: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
......@@ -266,6 +210,24 @@ const AddUser: React.FC<{}> = () => {
}
}
/>
<Modal
title="选择组织机构"
visible={originVisible}
onOk={handleOrigin}
onCancel={() => setOriginVisible(false)}
okText="确认"
cancelText="取消"
getContainer='#root'
// destroyOnClose={true}
>
<TabTree
fetchData = {params => fetchOriginTreeData(params)}
treeData={originTreeData}
handleSelect={(key, node) => handlePlateformSelect(key, node)}
actions={originTreeActions}
customKey="id"
/>
</Modal>
</div>
</DetailPage>
......
......@@ -174,6 +174,41 @@ export const findTreeKeys = (arr: any[], keyword?: string) => {
return results
}
// 树形结构降为一维对象处理
export const treeReduction = (data: any[]) => {
const hashMaps = {}
const selfData: any[] = deepClone(data)
while (selfData.length > 0) {
const useItem = selfData.shift()
// 存在子集
if (useItem.children && useItem.children.length > 0) {
useItem.children = useItem.children.map(v => {
v.parentId = useItem.id
return v
})
selfData.push(...useItem.children)
}
hashMaps[useItem.id] = useItem
}
return hashMaps
}
// 获取某一节点的title路径
export const getParentTreeTitles = (dataSouce, key) => {
const hashMaps = treeReduction(dataSouce)
let targetKey = key
let targetPath = ''
while (targetKey !== '') {
const title = hashMaps[targetKey].title
targetPath = targetPath === '' ? title : `${title}-${targetPath}`
targetKey = hashMaps[targetKey].parentId || ''
}
return targetPath
}
// 数组通过某个key进行去重合并, 并返回一个新数组
export const mergeArrByKey = (preArr: any[], nextArr: any[], target?: string) => {
const mergeArr = preArr.concat(nextArr)
......
......@@ -37,20 +37,6 @@ const errorMessage: httpStatus = {
504: "网关超时。",
};
const errorHandler = (error: ResponseError): IRequestError => {
const { response } = error
// http状态码非200的错误处理
const messageText = errorMessage[response.status]
if (response) {
message.error('http请求错误: ' + response.status + '->' + messageText, 3)
}
// throw可令响应promise走catch, 如需走resolve需直接return
throw {
message: messageText,
...error
}
}
const defaultHeaders = {
'Content-Type': 'Application/json',
'token': '21954519911775ff2c65fa5887b9b11b',
......@@ -69,7 +55,6 @@ const baseRequest = extend({
// 请求拦截器
baseRequest.interceptors.request.use((url: string, options: RequestOptionsInit): { url: string, options: RequestOptionsInit } => {
// 判断是否有权限
const loginAfterHeaders = getAuth()
const headers = {
......@@ -106,13 +91,12 @@ class ApiRequest {
baseRequest<IRequestSuccess<T>>(url, options).then(res => {
// 登录验证
if (res.code === 1101) {
message.error(res.message)
if (isDev) {
return ;
}
removeAuth()
history.replace('/login')
message.error(res.message)
return false
}
......
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