Compare commits
2 Commits
19c7d2ff28
...
219a945668
| Author | SHA1 | Date | |
|---|---|---|---|
| 219a945668 | |||
| f9f5ceac9d |
@@ -1,4 +1,7 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { getDruidIndexUrl } from '@/utils/publicUrl';
|
||||||
|
import { establishDruidSession } from '@/services/monitor/druid';
|
||||||
|
|
||||||
/* *
|
/* *
|
||||||
*
|
*
|
||||||
@@ -8,6 +11,32 @@ import React, { useEffect } from 'react';
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
const DruidInfo: React.FC = () => {
|
const DruidInfo: React.FC = () => {
|
||||||
|
const [druidLoginUrl, setDruidLoginUrl] = useState<string>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let active = true;
|
||||||
|
establishDruidSession()
|
||||||
|
.then((res) => {
|
||||||
|
if (!active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.code !== 200) {
|
||||||
|
message.error(res.msg || 'Druid 自动登录失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDruidLoginUrl(getDruidIndexUrl());
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (active) {
|
||||||
|
message.error('Druid 自动登录失败');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
active = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const frame = document.getElementById('bdIframe');
|
const frame = document.getElementById('bdIframe');
|
||||||
if (frame) {
|
if (frame) {
|
||||||
@@ -16,14 +45,14 @@ const DruidInfo: React.FC = () => {
|
|||||||
frame.style.width = `${Number(deviceWidth) - 220}px`;
|
frame.style.width = `${Number(deviceWidth) - 220}px`;
|
||||||
frame.style.height = `${Number(deviceHeight) - 120}px`;
|
frame.style.height = `${Number(deviceHeight) - 120}px`;
|
||||||
}
|
}
|
||||||
});
|
}, [druidLoginUrl]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<iframe
|
<iframe
|
||||||
style={{ width: '100%', border: '0px', height: '100%' }}
|
style={{ width: '100%', border: '0px', height: '100%' }}
|
||||||
src={process.env.NODE_ENV === 'development' ? '/api/druid/login.html' : '/api/ks/druid/login.html'}
|
src={druidLoginUrl}
|
||||||
id="bdIframe"
|
id="bdIframe"
|
||||||
/>
|
/>
|
||||||
// </WrapContent>
|
// </WrapContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,10 +23,11 @@ const handleAdd = async (fields: API.System.Dept) => {
|
|||||||
hide();
|
hide();
|
||||||
if (resp.code === 200) {
|
if (resp.code === 200) {
|
||||||
message.success('添加成功');
|
message.success('添加成功');
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
message.error(resp.msg);
|
message.error(resp.msg || '添加失败');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
hide();
|
hide();
|
||||||
message.error('添加失败请重试!');
|
message.error('添加失败请重试!');
|
||||||
@@ -46,10 +47,11 @@ const handleUpdate = async (fields: API.System.Dept) => {
|
|||||||
hide();
|
hide();
|
||||||
if (resp.code === 200) {
|
if (resp.code === 200) {
|
||||||
message.success('更新成功');
|
message.success('更新成功');
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
message.error(resp.msg);
|
message.error(resp.msg || '更新失败');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
hide();
|
hide();
|
||||||
message.error('配置失败请重试!');
|
message.error('配置失败请重试!');
|
||||||
@@ -70,10 +72,11 @@ const handleRemove = async (selectedRows: API.System.Dept[]) => {
|
|||||||
hide();
|
hide();
|
||||||
if (resp.code === 200) {
|
if (resp.code === 200) {
|
||||||
message.success('删除成功,即将刷新');
|
message.success('删除成功,即将刷新');
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
message.error(resp.msg);
|
message.error(resp.msg || '删除失败');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
hide();
|
hide();
|
||||||
message.error('删除失败,请重试');
|
message.error('删除失败,请重试');
|
||||||
@@ -90,10 +93,11 @@ const handleRemoveOne = async (selectedRow: API.System.Dept) => {
|
|||||||
hide();
|
hide();
|
||||||
if (resp.code === 200) {
|
if (resp.code === 200) {
|
||||||
message.success('删除成功,即将刷新');
|
message.success('删除成功,即将刷新');
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
message.error(resp.msg);
|
message.error(resp.msg || '删除失败');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
hide();
|
hide();
|
||||||
message.error('删除失败,请重试');
|
message.error('删除失败,请重试');
|
||||||
@@ -101,6 +105,16 @@ const handleRemoveOne = async (selectedRow: API.System.Dept) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取树表格中所有有下级部门的节点,确保异步加载后能够展开到任意层级。
|
||||||
|
*/
|
||||||
|
const getExpandableRowKeys = (nodes: any[]): React.Key[] =>
|
||||||
|
nodes.flatMap((node) => {
|
||||||
|
if (!Array.isArray(node.children) || node.children.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [node.deptId, ...getExpandableRowKeys(node.children)];
|
||||||
|
});
|
||||||
|
|
||||||
const DeptTableList: React.FC = () => {
|
const DeptTableList: React.FC = () => {
|
||||||
const formTableRef = useRef<FormInstance>();
|
const formTableRef = useRef<FormInstance>();
|
||||||
@@ -110,6 +124,7 @@ const DeptTableList: React.FC = () => {
|
|||||||
const actionRef = useRef<ActionType>();
|
const actionRef = useRef<ActionType>();
|
||||||
const [currentRow, setCurrentRow] = useState<API.System.Dept>();
|
const [currentRow, setCurrentRow] = useState<API.System.Dept>();
|
||||||
const [selectedRows, setSelectedRows] = useState<API.System.Dept[]>([]);
|
const [selectedRows, setSelectedRows] = useState<API.System.Dept[]>([]);
|
||||||
|
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
|
||||||
|
|
||||||
const [deptTree, setDeptTree] = useState<any>([]);
|
const [deptTree, setDeptTree] = useState<any>([]);
|
||||||
const [statusOptions, setStatusOptions] = useState<any>([]);
|
const [statusOptions, setStatusOptions] = useState<any>([]);
|
||||||
@@ -125,6 +140,22 @@ const DeptTableList: React.FC = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const openAddModal = async (parentId?: number) => {
|
||||||
|
const res = await getDeptList();
|
||||||
|
if (res.code !== 200) {
|
||||||
|
message.warning(res.msg || '部门列表加载失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDeptTree(buildTreeData(res.data, 'deptId', 'deptName', '', '', ''));
|
||||||
|
setCurrentRow(
|
||||||
|
parentId === undefined
|
||||||
|
? undefined
|
||||||
|
: ({ parentId, orderNum: 1, status: '0' } as API.System.Dept),
|
||||||
|
);
|
||||||
|
setModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
const columns: ProColumns<API.System.Dept>[] = [
|
const columns: ProColumns<API.System.Dept>[] = [
|
||||||
{
|
{
|
||||||
title: <FormattedMessage id="system.dept.dept_name" defaultMessage="部门名称" />,
|
title: <FormattedMessage id="system.dept.dept_name" defaultMessage="部门名称" />,
|
||||||
@@ -148,14 +179,14 @@ const DeptTableList: React.FC = () => {
|
|||||||
{
|
{
|
||||||
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
|
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
|
||||||
dataIndex: 'option',
|
dataIndex: 'option',
|
||||||
width: '220px',
|
width: '300px',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
render: (_, record) => [
|
render: (_, record) => [
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
key="edit"
|
key="edit"
|
||||||
hidden={!access.hasPerms('system:dept:edit.tsx')}
|
hidden={!access.hasPerms('system:dept:edit')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
getDeptListExcludeChild(record.deptId).then((res) => {
|
getDeptListExcludeChild(record.deptId).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@@ -174,6 +205,15 @@ const DeptTableList: React.FC = () => {
|
|||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>,
|
</Button>,
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
key="addChild"
|
||||||
|
hidden={!access.hasPerms('system:dept:add')}
|
||||||
|
onClick={() => openAddModal(record.deptId)}
|
||||||
|
>
|
||||||
|
<PlusOutlined /> 新增下级
|
||||||
|
</Button>,
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -218,22 +258,16 @@ const DeptTableList: React.FC = () => {
|
|||||||
search={{
|
search={{
|
||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
}}
|
}}
|
||||||
|
expandable={{
|
||||||
|
expandedRowKeys,
|
||||||
|
onExpandedRowsChange: (keys) => setExpandedRowKeys(keys),
|
||||||
|
}}
|
||||||
toolBarRender={() => [
|
toolBarRender={() => [
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
key="add"
|
key="add"
|
||||||
hidden={!access.hasPerms('system:dept:add')}
|
hidden={!access.hasPerms('system:dept:add')}
|
||||||
onClick={async () => {
|
onClick={() => openAddModal()}
|
||||||
getDeptList().then((res) => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
setDeptTree(buildTreeData(res.data, 'deptId', 'deptName', '', '', ''));
|
|
||||||
setCurrentRow(undefined);
|
|
||||||
setModalVisible(true);
|
|
||||||
} else {
|
|
||||||
message.warning(res.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
||||||
</Button>,
|
</Button>,
|
||||||
@@ -264,8 +298,10 @@ const DeptTableList: React.FC = () => {
|
|||||||
]}
|
]}
|
||||||
request={(params) =>
|
request={(params) =>
|
||||||
getDeptList({ ...params } as API.System.DeptListParams).then((res) => {
|
getDeptList({ ...params } as API.System.DeptListParams).then((res) => {
|
||||||
|
const treeData = buildTreeData(res.data, 'deptId', 'deptName', '', '', '');
|
||||||
|
setExpandedRowKeys(getExpandableRowKeys(treeData));
|
||||||
const result = {
|
const result = {
|
||||||
data: buildTreeData(res.data, 'deptId', '', '', '', ''),
|
data: treeData,
|
||||||
total: res.data.length,
|
total: res.data.length,
|
||||||
success: true,
|
success: true,
|
||||||
};
|
};
|
||||||
@@ -293,7 +329,7 @@ const DeptTableList: React.FC = () => {
|
|||||||
<Button
|
<Button
|
||||||
key="remove"
|
key="remove"
|
||||||
danger
|
danger
|
||||||
hidden={!access.hasPerms('system:dept:del')}
|
hidden={!access.hasPerms('system:dept:remove')}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '删除',
|
title: '删除',
|
||||||
|
|||||||
@@ -11,27 +11,52 @@ const { DirectoryTree } = Tree;
|
|||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
|
|
||||||
|
|
||||||
export type TreeProps = {
|
export type TreeProps = {
|
||||||
onSelect: (values: any) => Promise<void>;
|
onSelect: (values: any) => Promise<void>;
|
||||||
|
defaultDeptId?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAllNodeKeys = (nodes: any[]): React.Key[] =>
|
||||||
|
nodes.flatMap((node) => [node.key, ...(node.children ? getAllNodeKeys(node.children) : [])]);
|
||||||
|
|
||||||
const DeptTree: React.FC<TreeProps> = (props) => {
|
const DeptTree: React.FC<TreeProps> = (props) => {
|
||||||
const [treeData, setTreeData] = useState<any>([]);
|
const [treeData, setTreeData] = useState<any>([]);
|
||||||
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
||||||
|
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
|
||||||
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);
|
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);
|
||||||
|
|
||||||
|
const findNodeById = (nodes: any[], deptId?: number): any => {
|
||||||
|
if (!deptId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (Number(node.id) === deptId) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node.children) {
|
||||||
|
const matched = findNodeById(node.children, deptId);
|
||||||
|
if (matched) {
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
const fetchDeptList = async () => {
|
const fetchDeptList = async () => {
|
||||||
const hide = message.loading('正在查询');
|
const hide = message.loading('正在查询');
|
||||||
try {
|
try {
|
||||||
await getDeptTree({}).then((res: any) => {
|
const res = await getDeptTree({});
|
||||||
const exKeys = [];
|
setTreeData(res);
|
||||||
exKeys.push('1');
|
setExpandedKeys(getAllNodeKeys(res));
|
||||||
setTreeData(res);
|
|
||||||
exKeys.push(res[0].children[0].id);
|
const defaultNode = props.defaultDeptId
|
||||||
setExpandedKeys(exKeys);
|
? findNodeById(res, props.defaultDeptId)
|
||||||
props.onSelect(res[0].children[0]);
|
: res[0]?.children?.[0] || res[0];
|
||||||
});
|
if (defaultNode) {
|
||||||
|
setSelectedKeys([String(defaultNode.key ?? defaultNode.id)]);
|
||||||
|
props.onSelect(defaultNode);
|
||||||
|
}
|
||||||
hide();
|
hide();
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -45,6 +70,7 @@ const DeptTree: React.FC<TreeProps> = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onSelect = (keys: React.Key[], info: any) => {
|
const onSelect = (keys: React.Key[], info: any) => {
|
||||||
|
setSelectedKeys(keys);
|
||||||
props.onSelect(info.node);
|
props.onSelect(info.node);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,6 +85,7 @@ const DeptTree: React.FC<TreeProps> = (props) => {
|
|||||||
defaultExpandAll
|
defaultExpandAll
|
||||||
onExpand={onExpand}
|
onExpand={onExpand}
|
||||||
expandedKeys={expandedKeys}
|
expandedKeys={expandedKeys}
|
||||||
|
selectedKeys={selectedKeys}
|
||||||
autoExpandParent={autoExpandParent}
|
autoExpandParent={autoExpandParent}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
treeData={treeData}
|
treeData={treeData}
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ const UserForm: React.FC<UserFormProps> = (props) => {
|
|||||||
layout="horizontal"
|
layout="horizontal"
|
||||||
submitter={false}
|
submitter={false}
|
||||||
onFinish={handleFinish}>
|
onFinish={handleFinish}>
|
||||||
|
<Form.Item name="userId" hidden>
|
||||||
|
<input type="hidden" />
|
||||||
|
</Form.Item>
|
||||||
<ProFormText
|
<ProFormText
|
||||||
name="nickName"
|
name="nickName"
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
|
|
||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
|
import { useIntl, FormattedMessage, useAccess, useModel } from '@umijs/max';
|
||||||
import { Card, Col, Dropdown, FormInstance, Row, Space, Switch } from 'antd';
|
import { Card, Col, Dropdown, FormInstance, Radio, Row, Space, Switch } from 'antd';
|
||||||
import { Button, message, Modal } from 'antd';
|
import { Button, message, Modal } from 'antd';
|
||||||
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
|
import {
|
||||||
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
|
ActionType,
|
||||||
import { getUserList, removeUser, addUser, updateUser, exportUser, getUser, changeUserStatus, updateAuthRole, resetUserPwd } from '@/services/system/user';
|
FooterToolbar,
|
||||||
|
PageContainer,
|
||||||
|
ProColumns,
|
||||||
|
ProTable,
|
||||||
|
} from '@ant-design/pro-components';
|
||||||
|
import {
|
||||||
|
PlusOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
ExclamationCircleOutlined,
|
||||||
|
DownOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
getUserList,
|
||||||
|
removeUser,
|
||||||
|
addUser,
|
||||||
|
updateUser,
|
||||||
|
exportUser,
|
||||||
|
getUser,
|
||||||
|
changeUserStatus,
|
||||||
|
updateAuthRole,
|
||||||
|
resetUserPwd,
|
||||||
|
} from '@/services/system/user';
|
||||||
import UpdateForm from './edit';
|
import UpdateForm from './edit';
|
||||||
import { getDictValueEnum } from '@/services/system/dict';
|
import { getDictValueEnum } from '@/services/system/dict';
|
||||||
import { DataNode } from 'antd/es/tree';
|
import { DataNode } from 'antd/es/tree';
|
||||||
@@ -104,10 +125,10 @@ const handleRemoveOne = async (selectedRow: API.System.User) => {
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const handleExport = async () => {
|
const handleExport = async (params?: API.System.UserListParams) => {
|
||||||
const hide = message.loading('正在导出');
|
const hide = message.loading('正在导出');
|
||||||
try {
|
try {
|
||||||
await exportUser();
|
await exportUser(params);
|
||||||
hide();
|
hide();
|
||||||
message.success('导出成功');
|
message.success('导出成功');
|
||||||
return true;
|
return true;
|
||||||
@@ -120,6 +141,8 @@ const handleExport = async () => {
|
|||||||
|
|
||||||
const UserTableList: React.FC = () => {
|
const UserTableList: React.FC = () => {
|
||||||
const [messageApi, contextHolder] = message.useMessage();
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
|
const { initialState } = useModel('@@initialState');
|
||||||
|
const currentDeptId = Number((initialState?.currentUser as any)?.dept?.deptId || 0);
|
||||||
|
|
||||||
const formTableRef = useRef<FormInstance>();
|
const formTableRef = useRef<FormInstance>();
|
||||||
|
|
||||||
@@ -131,7 +154,8 @@ const UserTableList: React.FC = () => {
|
|||||||
const [currentRow, setCurrentRow] = useState<API.System.User>();
|
const [currentRow, setCurrentRow] = useState<API.System.User>();
|
||||||
const [selectedRows, setSelectedRows] = useState<API.System.User[]>([]);
|
const [selectedRows, setSelectedRows] = useState<API.System.User[]>([]);
|
||||||
|
|
||||||
const [selectDept, setSelectDept] = useState<any>({ id: 0 });
|
const [selectDept, setSelectDept] = useState<any>({ id: currentDeptId });
|
||||||
|
const [deptScope, setDeptScope] = useState<'SELF' | 'CHILDREN'>('SELF');
|
||||||
const [sexOptions, setSexOptions] = useState<any>([]);
|
const [sexOptions, setSexOptions] = useState<any>([]);
|
||||||
const [statusOptions, setStatusOptions] = useState<any>([]);
|
const [statusOptions, setStatusOptions] = useState<any>([]);
|
||||||
|
|
||||||
@@ -143,6 +167,18 @@ const UserTableList: React.FC = () => {
|
|||||||
|
|
||||||
const access = useAccess();
|
const access = useAccess();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentDeptId && !selectDept.id) {
|
||||||
|
setSelectDept({ id: currentDeptId });
|
||||||
|
}
|
||||||
|
}, [currentDeptId, selectDept.id]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectDept.id) {
|
||||||
|
actionRef.current?.reload();
|
||||||
|
}
|
||||||
|
}, [selectDept.id, deptScope]);
|
||||||
|
|
||||||
/** 国际化配置 */
|
/** 国际化配置 */
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
@@ -156,12 +192,12 @@ const UserTableList: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const showChangeStatusConfirm = (record: API.System.User) => {
|
const showChangeStatusConfirm = (record: API.System.User) => {
|
||||||
let text = record.status === "1" ? "启用" : "停用";
|
let text = record.status === '1' ? '启用' : '停用';
|
||||||
const newStatus = record.status === '0' ? '1' : '0';
|
const newStatus = record.status === '0' ? '1' : '0';
|
||||||
confirm({
|
confirm({
|
||||||
title: `确认要${text}${record.userName}用户吗?`,
|
title: `确认要${text}${record.userName}用户吗?`,
|
||||||
onOk() {
|
onOk() {
|
||||||
changeUserStatus(record.userId, newStatus).then(resp => {
|
changeUserStatus(record.userId, newStatus).then((resp) => {
|
||||||
if (resp.code === 200) {
|
if (resp.code === 200) {
|
||||||
messageApi.open({
|
messageApi.open({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@@ -221,7 +257,7 @@ const UserTableList: React.FC = () => {
|
|||||||
title: <FormattedMessage id="system.user.dept_name" defaultMessage="部门" />,
|
title: <FormattedMessage id="system.user.dept_name" defaultMessage="部门" />,
|
||||||
dataIndex: ['dept', 'deptName'],
|
dataIndex: ['dept', 'deptName'],
|
||||||
valueType: 'text',
|
valueType: 'text',
|
||||||
hideInSearch: true
|
hideInSearch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
|
title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
|
||||||
@@ -241,7 +277,8 @@ const UserTableList: React.FC = () => {
|
|||||||
unCheckedChildren="停用"
|
unCheckedChildren="停用"
|
||||||
defaultChecked
|
defaultChecked
|
||||||
onClick={() => showChangeStatusConfirm(record)}
|
onClick={() => showChangeStatusConfirm(record)}
|
||||||
/>)
|
/>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -297,7 +334,9 @@ const UserTableList: React.FC = () => {
|
|||||||
menu={{
|
menu={{
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: <FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />,
|
label: (
|
||||||
|
<FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />
|
||||||
|
),
|
||||||
key: 'reset',
|
key: 'reset',
|
||||||
disabled: !access.hasPerms('system:user:edit.tsx'),
|
disabled: !access.hasPerms('system:user:edit.tsx'),
|
||||||
},
|
},
|
||||||
@@ -311,13 +350,12 @@ const UserTableList: React.FC = () => {
|
|||||||
if (key === 'reset') {
|
if (key === 'reset') {
|
||||||
setResetPwdModalVisible(true);
|
setResetPwdModalVisible(true);
|
||||||
setCurrentRow(record);
|
setCurrentRow(record);
|
||||||
}
|
} else if (key === 'authRole') {
|
||||||
else if (key === 'authRole') {
|
|
||||||
fetchUserInfo(record.userId);
|
fetchUserInfo(record.userId);
|
||||||
setAuthRoleModalVisible(true);
|
setAuthRoleModalVisible(true);
|
||||||
setCurrentRow(record);
|
setCurrentRow(record);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<a onClick={(e) => e.preventDefault()}>
|
<a onClick={(e) => e.preventDefault()}>
|
||||||
@@ -338,11 +376,9 @@ const UserTableList: React.FC = () => {
|
|||||||
<Col lg={6} md={24}>
|
<Col lg={6} md={24}>
|
||||||
<Card>
|
<Card>
|
||||||
<DeptTree
|
<DeptTree
|
||||||
|
defaultDeptId={currentDeptId}
|
||||||
onSelect={async (value: any) => {
|
onSelect={async (value: any) => {
|
||||||
setSelectDept(value);
|
setSelectDept(value);
|
||||||
if (actionRef.current) {
|
|
||||||
formTableRef?.current?.submit();
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -361,6 +397,18 @@ const UserTableList: React.FC = () => {
|
|||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
}}
|
}}
|
||||||
toolBarRender={() => [
|
toolBarRender={() => [
|
||||||
|
<Radio.Group
|
||||||
|
key="deptScope"
|
||||||
|
optionType="button"
|
||||||
|
buttonStyle="solid"
|
||||||
|
value={deptScope}
|
||||||
|
onChange={(event) => {
|
||||||
|
setDeptScope(event.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Radio.Button value="SELF">查看本级</Radio.Button>
|
||||||
|
<Radio.Button value="CHILDREN">查看本级及下属</Radio.Button>
|
||||||
|
</Radio.Group>,
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
key="add"
|
key="add"
|
||||||
@@ -369,7 +417,7 @@ const UserTableList: React.FC = () => {
|
|||||||
const treeData = await getDeptTree({});
|
const treeData = await getDeptTree({});
|
||||||
setDeptTree(treeData);
|
setDeptTree(treeData);
|
||||||
|
|
||||||
const postResp = await getPostList()
|
const postResp = await getPostList();
|
||||||
if (postResp.code === 200) {
|
if (postResp.code === 200) {
|
||||||
setPostList(
|
setPostList(
|
||||||
postResp.rows.map((item: any) => {
|
postResp.rows.map((item: any) => {
|
||||||
@@ -381,7 +429,7 @@ const UserTableList: React.FC = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const roleResp = await getRoleList()
|
const roleResp = await getRoleList();
|
||||||
if (roleResp.code === 200) {
|
if (roleResp.code === 200) {
|
||||||
setRoleList(
|
setRoleList(
|
||||||
roleResp.rows.map((item: any) => {
|
roleResp.rows.map((item: any) => {
|
||||||
@@ -396,7 +444,8 @@ const UserTableList: React.FC = () => {
|
|||||||
setModalVisible(true);
|
setModalVisible(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
<PlusOutlined />{' '}
|
||||||
|
<FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
||||||
</Button>,
|
</Button>,
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -415,7 +464,7 @@ const UserTableList: React.FC = () => {
|
|||||||
actionRef.current?.reloadAndRest?.();
|
actionRef.current?.reloadAndRest?.();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCancel() { },
|
onCancel() {},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -427,7 +476,7 @@ const UserTableList: React.FC = () => {
|
|||||||
key="export"
|
key="export"
|
||||||
hidden={!access.hasPerms('system:user:export')}
|
hidden={!access.hasPerms('system:user:export')}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
handleExport();
|
handleExport({ deptId: selectDept.id, deptScope });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlusOutlined />
|
<PlusOutlined />
|
||||||
@@ -435,7 +484,11 @@ const UserTableList: React.FC = () => {
|
|||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
request={(params) =>
|
request={(params) =>
|
||||||
getUserList({ ...params, deptId: selectDept.id } as API.System.UserListParams).then((res) => {
|
getUserList({
|
||||||
|
...params,
|
||||||
|
deptId: selectDept.id,
|
||||||
|
deptScope,
|
||||||
|
} as API.System.UserListParams).then((res) => {
|
||||||
const result = {
|
const result = {
|
||||||
data: res.rows,
|
data: res.rows,
|
||||||
total: res.total,
|
total: res.total,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { getProductionApiBaseUrl } from '@/utils/publicUrl';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -7,6 +8,11 @@ import React, { useEffect } from 'react';
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
const CacheInfo: React.FC = () => {
|
const CacheInfo: React.FC = () => {
|
||||||
|
const swaggerUrl =
|
||||||
|
process.env.NODE_ENV === 'development'
|
||||||
|
? '/api/swagger-ui/index.html'
|
||||||
|
: `${getProductionApiBaseUrl()}swagger-ui/index.html`;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const frame = document.getElementById('bdIframe');
|
const frame = document.getElementById('bdIframe');
|
||||||
if (frame) {
|
if (frame) {
|
||||||
@@ -21,7 +27,7 @@ const CacheInfo: React.FC = () => {
|
|||||||
<div style={{}}>
|
<div style={{}}>
|
||||||
<iframe
|
<iframe
|
||||||
style={{ width: '100%', border: '0px', height: '100%' }}
|
style={{ width: '100%', border: '0px', height: '100%' }}
|
||||||
src={process.env.NODE_ENV === 'development' ? '/api/swagger-ui/index.html' : '/api/ks/swagger-ui/index.html'}
|
src={swaggerUrl}
|
||||||
id="bdIframe"
|
id="bdIframe"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
12
src/services/monitor/druid.ts
Normal file
12
src/services/monitor/druid.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { request } from '@umijs/max';
|
||||||
|
|
||||||
|
export interface DruidSsoResponse {
|
||||||
|
code: number;
|
||||||
|
msg?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function establishDruidSession() {
|
||||||
|
return request<DruidSsoResponse>('/api/monitor/druid/sso', {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
6
src/types/system/user.d.ts
vendored
6
src/types/system/user.d.ts
vendored
@@ -1,6 +1,4 @@
|
|||||||
|
|
||||||
declare namespace API.System {
|
declare namespace API.System {
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
userId: number;
|
userId: number;
|
||||||
deptId: number;
|
deptId: number;
|
||||||
@@ -26,6 +24,7 @@ declare namespace API.System {
|
|||||||
export interface UserListParams {
|
export interface UserListParams {
|
||||||
userId?: string;
|
userId?: string;
|
||||||
deptId?: string;
|
deptId?: string;
|
||||||
|
deptScope?: 'SELF' | 'CHILDREN';
|
||||||
userName?: string;
|
userName?: string;
|
||||||
nickName?: string;
|
nickName?: string;
|
||||||
userType?: string;
|
userType?: string;
|
||||||
@@ -61,11 +60,10 @@ declare namespace API.System {
|
|||||||
roles: [];
|
roles: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserPageResult {
|
export interface UserPageResult {
|
||||||
code: number;
|
code: number;
|
||||||
msg: string;
|
msg: string;
|
||||||
total: number;
|
total: number;
|
||||||
rows: Array<User>;
|
rows: Array<User>;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,17 @@ export function getProductionApiBaseUrl(origin = getBrowserOrigin()) {
|
|||||||
return `${normalizedOrigin || ''}/api/shihezi/`;
|
return `${normalizedOrigin || ''}/api/shihezi/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回已经建立登录态后的 Druid 首页地址。
|
||||||
|
*/
|
||||||
|
export function getDruidIndexUrl(origin = getBrowserOrigin()) {
|
||||||
|
const druidIndexPath = 'druid/index.html';
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
return `/api/${druidIndexPath}`;
|
||||||
|
}
|
||||||
|
return `${getProductionApiBaseUrl(origin)}${druidIndexPath}`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 后端可能因为反向代理配置返回内网 H5 地址,前端展示和打开二维码时使用当前公开 origin。
|
* 后端可能因为反向代理配置返回内网 H5 地址,前端展示和打开二维码时使用当前公开 origin。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getProductionApiBaseUrl, normalizePublicUrl } from '@/utils/publicUrl';
|
import { getDruidIndexUrl, getProductionApiBaseUrl, normalizePublicUrl } from '@/utils/publicUrl';
|
||||||
|
|
||||||
describe('public URL helpers', () => {
|
describe('public URL helpers', () => {
|
||||||
it('builds the production API base URL from the browser origin', () => {
|
it('builds the production API base URL from the browser origin', () => {
|
||||||
@@ -7,6 +7,12 @@ describe('public URL helpers', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('builds the Druid index URL from the public API base URL', () => {
|
||||||
|
expect(getDruidIndexUrl('http://47.111.103.66')).toBe(
|
||||||
|
'http://47.111.103.66/api/shihezi/druid/index.html',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('replaces an internal backend origin with the browser origin', () => {
|
it('replaces an internal backend origin with the browser origin', () => {
|
||||||
expect(
|
expect(
|
||||||
normalizePublicUrl(
|
normalizePublicUrl(
|
||||||
|
|||||||
Reference in New Issue
Block a user