feat: enhance Druid integration and improve user management features
This commit is contained in:
@@ -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 [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(() => {
|
||||
const frame = document.getElementById('bdIframe');
|
||||
if (frame) {
|
||||
@@ -16,14 +45,14 @@ const DruidInfo: React.FC = () => {
|
||||
frame.style.width = `${Number(deviceWidth) - 220}px`;
|
||||
frame.style.height = `${Number(deviceHeight) - 120}px`;
|
||||
}
|
||||
});
|
||||
}, [druidLoginUrl]);
|
||||
|
||||
return (
|
||||
<iframe
|
||||
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"
|
||||
/>
|
||||
/>
|
||||
// </WrapContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -23,10 +23,11 @@ const handleAdd = async (fields: API.System.Dept) => {
|
||||
hide();
|
||||
if (resp.code === 200) {
|
||||
message.success('添加成功');
|
||||
return true;
|
||||
} else {
|
||||
message.error(resp.msg);
|
||||
message.error(resp.msg || '添加失败');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
hide();
|
||||
message.error('添加失败请重试!');
|
||||
@@ -46,10 +47,11 @@ const handleUpdate = async (fields: API.System.Dept) => {
|
||||
hide();
|
||||
if (resp.code === 200) {
|
||||
message.success('更新成功');
|
||||
return true;
|
||||
} else {
|
||||
message.error(resp.msg);
|
||||
message.error(resp.msg || '更新失败');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
hide();
|
||||
message.error('配置失败请重试!');
|
||||
@@ -70,10 +72,11 @@ const handleRemove = async (selectedRows: API.System.Dept[]) => {
|
||||
hide();
|
||||
if (resp.code === 200) {
|
||||
message.success('删除成功,即将刷新');
|
||||
return true;
|
||||
} else {
|
||||
message.error(resp.msg);
|
||||
message.error(resp.msg || '删除失败');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
hide();
|
||||
message.error('删除失败,请重试');
|
||||
@@ -90,10 +93,11 @@ const handleRemoveOne = async (selectedRow: API.System.Dept) => {
|
||||
hide();
|
||||
if (resp.code === 200) {
|
||||
message.success('删除成功,即将刷新');
|
||||
return true;
|
||||
} else {
|
||||
message.error(resp.msg);
|
||||
message.error(resp.msg || '删除失败');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
hide();
|
||||
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 formTableRef = useRef<FormInstance>();
|
||||
@@ -110,6 +124,7 @@ const DeptTableList: React.FC = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [currentRow, setCurrentRow] = useState<API.System.Dept>();
|
||||
const [selectedRows, setSelectedRows] = useState<API.System.Dept[]>([]);
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const [deptTree, setDeptTree] = 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>[] = [
|
||||
{
|
||||
title: <FormattedMessage id="system.dept.dept_name" defaultMessage="部门名称" />,
|
||||
@@ -148,14 +179,14 @@ const DeptTableList: React.FC = () => {
|
||||
{
|
||||
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
|
||||
dataIndex: 'option',
|
||||
width: '220px',
|
||||
width: '300px',
|
||||
valueType: 'option',
|
||||
render: (_, record) => [
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
key="edit"
|
||||
hidden={!access.hasPerms('system:dept:edit.tsx')}
|
||||
hidden={!access.hasPerms('system:dept:edit')}
|
||||
onClick={() => {
|
||||
getDeptListExcludeChild(record.deptId).then((res) => {
|
||||
if (res.code === 200) {
|
||||
@@ -174,6 +205,15 @@ const DeptTableList: React.FC = () => {
|
||||
>
|
||||
编辑
|
||||
</Button>,
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
key="addChild"
|
||||
hidden={!access.hasPerms('system:dept:add')}
|
||||
onClick={() => openAddModal(record.deptId)}
|
||||
>
|
||||
<PlusOutlined /> 新增下级
|
||||
</Button>,
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@@ -218,22 +258,16 @@ const DeptTableList: React.FC = () => {
|
||||
search={{
|
||||
labelWidth: 120,
|
||||
}}
|
||||
expandable={{
|
||||
expandedRowKeys,
|
||||
onExpandedRowsChange: (keys) => setExpandedRowKeys(keys),
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button
|
||||
type="primary"
|
||||
key="add"
|
||||
hidden={!access.hasPerms('system:dept:add')}
|
||||
onClick={async () => {
|
||||
getDeptList().then((res) => {
|
||||
if (res.code === 200) {
|
||||
setDeptTree(buildTreeData(res.data, 'deptId', 'deptName', '', '', ''));
|
||||
setCurrentRow(undefined);
|
||||
setModalVisible(true);
|
||||
} else {
|
||||
message.warning(res.msg);
|
||||
}
|
||||
});
|
||||
}}
|
||||
onClick={() => openAddModal()}
|
||||
>
|
||||
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
||||
</Button>,
|
||||
@@ -264,8 +298,10 @@ const DeptTableList: React.FC = () => {
|
||||
]}
|
||||
request={(params) =>
|
||||
getDeptList({ ...params } as API.System.DeptListParams).then((res) => {
|
||||
const treeData = buildTreeData(res.data, 'deptId', 'deptName', '', '', '');
|
||||
setExpandedRowKeys(getExpandableRowKeys(treeData));
|
||||
const result = {
|
||||
data: buildTreeData(res.data, 'deptId', '', '', '', ''),
|
||||
data: treeData,
|
||||
total: res.data.length,
|
||||
success: true,
|
||||
};
|
||||
@@ -293,7 +329,7 @@ const DeptTableList: React.FC = () => {
|
||||
<Button
|
||||
key="remove"
|
||||
danger
|
||||
hidden={!access.hasPerms('system:dept:del')}
|
||||
hidden={!access.hasPerms('system:dept:remove')}
|
||||
onClick={async () => {
|
||||
Modal.confirm({
|
||||
title: '删除',
|
||||
|
||||
@@ -11,27 +11,52 @@ const { DirectoryTree } = Tree;
|
||||
*
|
||||
* */
|
||||
|
||||
|
||||
export type TreeProps = {
|
||||
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 [treeData, setTreeData] = useState<any>([]);
|
||||
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
||||
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
|
||||
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 hide = message.loading('正在查询');
|
||||
try {
|
||||
await getDeptTree({}).then((res: any) => {
|
||||
const exKeys = [];
|
||||
exKeys.push('1');
|
||||
setTreeData(res);
|
||||
exKeys.push(res[0].children[0].id);
|
||||
setExpandedKeys(exKeys);
|
||||
props.onSelect(res[0].children[0]);
|
||||
});
|
||||
const res = await getDeptTree({});
|
||||
setTreeData(res);
|
||||
setExpandedKeys(getAllNodeKeys(res));
|
||||
|
||||
const defaultNode = props.defaultDeptId
|
||||
? findNodeById(res, props.defaultDeptId)
|
||||
: res[0]?.children?.[0] || res[0];
|
||||
if (defaultNode) {
|
||||
setSelectedKeys([String(defaultNode.key ?? defaultNode.id)]);
|
||||
props.onSelect(defaultNode);
|
||||
}
|
||||
hide();
|
||||
return true;
|
||||
} catch (error) {
|
||||
@@ -45,6 +70,7 @@ const DeptTree: React.FC<TreeProps> = (props) => {
|
||||
}, []);
|
||||
|
||||
const onSelect = (keys: React.Key[], info: any) => {
|
||||
setSelectedKeys(keys);
|
||||
props.onSelect(info.node);
|
||||
};
|
||||
|
||||
@@ -59,6 +85,7 @@ const DeptTree: React.FC<TreeProps> = (props) => {
|
||||
defaultExpandAll
|
||||
onExpand={onExpand}
|
||||
expandedKeys={expandedKeys}
|
||||
selectedKeys={selectedKeys}
|
||||
autoExpandParent={autoExpandParent}
|
||||
onSelect={onSelect}
|
||||
treeData={treeData}
|
||||
|
||||
@@ -92,6 +92,9 @@ const UserForm: React.FC<UserFormProps> = (props) => {
|
||||
layout="horizontal"
|
||||
submitter={false}
|
||||
onFinish={handleFinish}>
|
||||
<Form.Item name="userId" hidden>
|
||||
<input type="hidden" />
|
||||
</Form.Item>
|
||||
<ProFormText
|
||||
name="nickName"
|
||||
label={intl.formatMessage({
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
|
||||
import { Card, Col, Dropdown, FormInstance, Row, Space, Switch } from 'antd';
|
||||
import { useIntl, FormattedMessage, useAccess, useModel } from '@umijs/max';
|
||||
import { Card, Col, Dropdown, FormInstance, Radio, Row, Space, Switch } from 'antd';
|
||||
import { Button, message, Modal } from 'antd';
|
||||
import { ActionType, 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 {
|
||||
ActionType,
|
||||
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 { getDictValueEnum } from '@/services/system/dict';
|
||||
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('正在导出');
|
||||
try {
|
||||
await exportUser();
|
||||
await exportUser(params);
|
||||
hide();
|
||||
message.success('导出成功');
|
||||
return true;
|
||||
@@ -120,6 +141,8 @@ const handleExport = async () => {
|
||||
|
||||
const UserTableList: React.FC = () => {
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const currentDeptId = Number((initialState?.currentUser as any)?.dept?.deptId || 0);
|
||||
|
||||
const formTableRef = useRef<FormInstance>();
|
||||
|
||||
@@ -131,7 +154,8 @@ const UserTableList: React.FC = () => {
|
||||
const [currentRow, setCurrentRow] = 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 [statusOptions, setStatusOptions] = useState<any>([]);
|
||||
|
||||
@@ -143,6 +167,18 @@ const UserTableList: React.FC = () => {
|
||||
|
||||
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();
|
||||
|
||||
@@ -156,12 +192,12 @@ const UserTableList: React.FC = () => {
|
||||
}, []);
|
||||
|
||||
const showChangeStatusConfirm = (record: API.System.User) => {
|
||||
let text = record.status === "1" ? "启用" : "停用";
|
||||
let text = record.status === '1' ? '启用' : '停用';
|
||||
const newStatus = record.status === '0' ? '1' : '0';
|
||||
confirm({
|
||||
title: `确认要${text}${record.userName}用户吗?`,
|
||||
onOk() {
|
||||
changeUserStatus(record.userId, newStatus).then(resp => {
|
||||
changeUserStatus(record.userId, newStatus).then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
messageApi.open({
|
||||
type: 'success',
|
||||
@@ -221,7 +257,7 @@ const UserTableList: React.FC = () => {
|
||||
title: <FormattedMessage id="system.user.dept_name" defaultMessage="部门" />,
|
||||
dataIndex: ['dept', 'deptName'],
|
||||
valueType: 'text',
|
||||
hideInSearch: true
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
|
||||
@@ -241,7 +277,8 @@ const UserTableList: React.FC = () => {
|
||||
unCheckedChildren="停用"
|
||||
defaultChecked
|
||||
onClick={() => showChangeStatusConfirm(record)}
|
||||
/>)
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -297,7 +334,9 @@ const UserTableList: React.FC = () => {
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
label: <FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />,
|
||||
label: (
|
||||
<FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />
|
||||
),
|
||||
key: 'reset',
|
||||
disabled: !access.hasPerms('system:user:edit.tsx'),
|
||||
},
|
||||
@@ -311,13 +350,12 @@ const UserTableList: React.FC = () => {
|
||||
if (key === 'reset') {
|
||||
setResetPwdModalVisible(true);
|
||||
setCurrentRow(record);
|
||||
}
|
||||
else if (key === 'authRole') {
|
||||
} else if (key === 'authRole') {
|
||||
fetchUserInfo(record.userId);
|
||||
setAuthRoleModalVisible(true);
|
||||
setCurrentRow(record);
|
||||
}
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<a onClick={(e) => e.preventDefault()}>
|
||||
@@ -338,11 +376,9 @@ const UserTableList: React.FC = () => {
|
||||
<Col lg={6} md={24}>
|
||||
<Card>
|
||||
<DeptTree
|
||||
defaultDeptId={currentDeptId}
|
||||
onSelect={async (value: any) => {
|
||||
setSelectDept(value);
|
||||
if (actionRef.current) {
|
||||
formTableRef?.current?.submit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
@@ -361,6 +397,18 @@ const UserTableList: React.FC = () => {
|
||||
labelWidth: 120,
|
||||
}}
|
||||
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
|
||||
type="primary"
|
||||
key="add"
|
||||
@@ -369,7 +417,7 @@ const UserTableList: React.FC = () => {
|
||||
const treeData = await getDeptTree({});
|
||||
setDeptTree(treeData);
|
||||
|
||||
const postResp = await getPostList()
|
||||
const postResp = await getPostList();
|
||||
if (postResp.code === 200) {
|
||||
setPostList(
|
||||
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) {
|
||||
setRoleList(
|
||||
roleResp.rows.map((item: any) => {
|
||||
@@ -396,7 +444,8 @@ const UserTableList: React.FC = () => {
|
||||
setModalVisible(true);
|
||||
}}
|
||||
>
|
||||
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
||||
<PlusOutlined />{' '}
|
||||
<FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
|
||||
</Button>,
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -415,7 +464,7 @@ const UserTableList: React.FC = () => {
|
||||
actionRef.current?.reloadAndRest?.();
|
||||
}
|
||||
},
|
||||
onCancel() { },
|
||||
onCancel() {},
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -427,7 +476,7 @@ const UserTableList: React.FC = () => {
|
||||
key="export"
|
||||
hidden={!access.hasPerms('system:user:export')}
|
||||
onClick={async () => {
|
||||
handleExport();
|
||||
handleExport({ deptId: selectDept.id, deptScope });
|
||||
}}
|
||||
>
|
||||
<PlusOutlined />
|
||||
@@ -435,7 +484,11 @@ const UserTableList: React.FC = () => {
|
||||
</Button>,
|
||||
]}
|
||||
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 = {
|
||||
data: res.rows,
|
||||
total: res.total,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { getProductionApiBaseUrl } from '@/utils/publicUrl';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -7,6 +8,11 @@ import React, { useEffect } from 'react';
|
||||
* */
|
||||
|
||||
const CacheInfo: React.FC = () => {
|
||||
const swaggerUrl =
|
||||
process.env.NODE_ENV === 'development'
|
||||
? '/api/swagger-ui/index.html'
|
||||
: `${getProductionApiBaseUrl()}swagger-ui/index.html`;
|
||||
|
||||
useEffect(() => {
|
||||
const frame = document.getElementById('bdIframe');
|
||||
if (frame) {
|
||||
@@ -21,7 +27,7 @@ const CacheInfo: React.FC = () => {
|
||||
<div style={{}}>
|
||||
<iframe
|
||||
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"
|
||||
/>
|
||||
</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 {
|
||||
|
||||
interface User {
|
||||
userId: number;
|
||||
deptId: number;
|
||||
@@ -26,6 +24,7 @@ declare namespace API.System {
|
||||
export interface UserListParams {
|
||||
userId?: string;
|
||||
deptId?: string;
|
||||
deptScope?: 'SELF' | 'CHILDREN';
|
||||
userName?: string;
|
||||
nickName?: string;
|
||||
userType?: string;
|
||||
@@ -61,11 +60,10 @@ declare namespace API.System {
|
||||
roles: [];
|
||||
}
|
||||
|
||||
export interface UserPageResult {
|
||||
export interface UserPageResult {
|
||||
code: number;
|
||||
msg: string;
|
||||
total: number;
|
||||
rows: Array<User>;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,17 @@ export function getProductionApiBaseUrl(origin = getBrowserOrigin()) {
|
||||
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。
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getProductionApiBaseUrl, normalizePublicUrl } from '@/utils/publicUrl';
|
||||
import { getDruidIndexUrl, getProductionApiBaseUrl, normalizePublicUrl } from '@/utils/publicUrl';
|
||||
|
||||
describe('public URL helpers', () => {
|
||||
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', () => {
|
||||
expect(
|
||||
normalizePublicUrl(
|
||||
|
||||
Reference in New Issue
Block a user