feat: custom table with row children
This commit is contained in:
+29
-3
@@ -1,12 +1,38 @@
|
||||
import { RequestConfig } from '@umijs/max';
|
||||
import { RequestConfig, history } from '@umijs/max';
|
||||
import { requestConfig } from './request-config';
|
||||
import { queryCurrentUserState } from './services/profile/apis';
|
||||
|
||||
const loginPath = '/login';
|
||||
// 运行时配置
|
||||
|
||||
// 全局初始化数据配置,用于 Layout 用户信息和权限初始化
|
||||
// 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate
|
||||
export async function getInitialState(): Promise<{ name: string }> {
|
||||
console.log('getInitialState+++++++++++++++');
|
||||
export async function getInitialState() {
|
||||
// 如果不是登录页面,执行
|
||||
const { location } = history;
|
||||
|
||||
const fetchUserInfo = async () => {
|
||||
try {
|
||||
const data = await queryCurrentUserState({
|
||||
skipErrorHandler: true
|
||||
});
|
||||
return data;
|
||||
} catch (error) {
|
||||
history.push(loginPath);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
if (![loginPath].includes(location.pathname)) {
|
||||
const currentUser = await fetchUserInfo();
|
||||
return {
|
||||
fetchUserInfo,
|
||||
name: 'admin',
|
||||
...currentUser
|
||||
};
|
||||
}
|
||||
return {
|
||||
fetchUserInfo,
|
||||
name: 'admin'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import classNames from 'classnames';
|
||||
import React, { useContext } from 'react';
|
||||
import RowContext from '../row-context';
|
||||
import '../styles/cell.less';
|
||||
import { SealColumnProps } from '../types';
|
||||
|
||||
const SealColumn: React.FC<SealColumnProps> = (props) => {
|
||||
const row: Record<string, any> = useContext(RowContext);
|
||||
const { dataIndex, render, align } = props;
|
||||
return (
|
||||
<div
|
||||
className={classNames('cell', {
|
||||
'cell-left': align === 'left',
|
||||
'cell-center': align === 'center',
|
||||
'cell-right': align === 'right'
|
||||
})}
|
||||
>
|
||||
<span className="cell-content">
|
||||
{render
|
||||
? render(row[dataIndex], { ...row, dataIndex })
|
||||
: row[dataIndex]}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SealColumn);
|
||||
@@ -0,0 +1,24 @@
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import '../styles/header.less';
|
||||
import { TableHeaderProps } from '../types';
|
||||
|
||||
const TableHeader: React.FC<TableHeaderProps> = (props) => {
|
||||
const { title, style, align, firstCell, lastCell } = props;
|
||||
return (
|
||||
<div
|
||||
style={{ ...style }}
|
||||
className={classNames('table-header', {
|
||||
'table-header-left': align === 'left',
|
||||
'table-header-center': align === 'center',
|
||||
'table-header-right': align === 'right',
|
||||
'table-header-first': firstCell,
|
||||
'table-header-last': lastCell
|
||||
})}
|
||||
>
|
||||
<div className="table-header-cell">{title}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(TableHeader);
|
||||
@@ -0,0 +1,137 @@
|
||||
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { Button, Checkbox, Col, Row } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import RowContext from '../row-context';
|
||||
import { RowContextProps, SealTableProps } from '../types';
|
||||
|
||||
const TableRow: React.FC<
|
||||
RowContextProps &
|
||||
Omit<SealTableProps, 'dataSource' | 'loading' | 'children' | 'empty'>
|
||||
> = (props) => {
|
||||
const {
|
||||
record,
|
||||
rowIndex,
|
||||
expandable,
|
||||
rowSelection,
|
||||
rowKey,
|
||||
columns,
|
||||
onExpand
|
||||
} = props;
|
||||
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [checked, setChecked] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (rowSelection) {
|
||||
const { selectedRowKeys } = rowSelection;
|
||||
if (selectedRowKeys.includes(record[rowKey])) {
|
||||
setChecked(true);
|
||||
} else {
|
||||
setChecked(false);
|
||||
}
|
||||
}
|
||||
}, [rowSelection]);
|
||||
|
||||
const handleRowExpand = () => {
|
||||
setExpanded(!expanded);
|
||||
onExpand?.(!expanded, record);
|
||||
};
|
||||
|
||||
const handleSelectChange = (e: any) => {
|
||||
if (e.target.checked) {
|
||||
// update selectedRowKeys
|
||||
rowSelection?.onChange(
|
||||
_.uniq([...rowSelection?.selectedRowKeys, record[rowKey]])
|
||||
);
|
||||
} else {
|
||||
// update selectedRowKeys
|
||||
rowSelection?.onChange(
|
||||
rowSelection?.selectedRowKeys.filter((key) => key !== record[rowKey])
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderRowPrefix = () => {
|
||||
if (expandable && rowSelection) {
|
||||
return (
|
||||
<div className="row-prefix-wrapper">
|
||||
<span style={{ marginRight: 5 }}>
|
||||
{_.isBoolean(expandable) ? (
|
||||
<Button type="text" size="small" onClick={handleRowExpand}>
|
||||
{expanded ? <DownOutlined /> : <RightOutlined />}
|
||||
</Button>
|
||||
) : (
|
||||
expandable
|
||||
)}
|
||||
</span>
|
||||
<Checkbox onChange={handleSelectChange} checked={checked}></Checkbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (expandable) {
|
||||
return (
|
||||
<div className="row-prefix-wrapper">
|
||||
{_.isBoolean(expandable) ? (
|
||||
<Button type="text" size="small" onClick={handleRowExpand}>
|
||||
{expanded ? <DownOutlined /> : <RightOutlined />}
|
||||
</Button>
|
||||
) : (
|
||||
expandable
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (rowSelection) {
|
||||
return (
|
||||
<div className="row-prefix-wrapper">
|
||||
{
|
||||
<Checkbox
|
||||
onChange={handleSelectChange}
|
||||
checked={checked}
|
||||
></Checkbox>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<RowContext.Provider value={{ ...record, rowIndex }}>
|
||||
<div className="row-box">
|
||||
<div
|
||||
className={classNames('row-wrapper', {
|
||||
'row-wrapper-selected': checked
|
||||
})}
|
||||
>
|
||||
{renderRowPrefix()}
|
||||
<Row className="seal-table-row">
|
||||
{React.Children.map(columns, (child) => {
|
||||
const { props: columnProps } = child as any;
|
||||
if (React.isValidElement(child)) {
|
||||
return (
|
||||
<Col
|
||||
key={`${columnProps.dataIndex}-${rowIndex}`}
|
||||
span={columnProps.span}
|
||||
>
|
||||
{child}
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
return <Col span={columnProps.span}></Col>;
|
||||
})}
|
||||
</Row>
|
||||
</div>
|
||||
{expanded && (
|
||||
<div className="expanded-row">
|
||||
<div className="expanded-row-content">rowchildren</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</RowContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableRow;
|
||||
@@ -0,0 +1,145 @@
|
||||
import { RightOutlined } from '@ant-design/icons';
|
||||
import { Button, Checkbox, Col, Empty, Row, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import TableHeader from './components/table-header';
|
||||
import TableRow from './components/table-row';
|
||||
import './styles/index.less';
|
||||
import { SealColumnProps, SealTableProps } from './types';
|
||||
|
||||
const SealTable: React.FC<SealTableProps> = (props) => {
|
||||
const { children, rowKey, onExpand, loading, expandable, rowSelection } =
|
||||
props;
|
||||
|
||||
const [selectAll, setSelectAll] = useState(false);
|
||||
const [indeterminate, setIndeterminate] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (rowSelection) {
|
||||
const { selectedRowKeys } = rowSelection;
|
||||
if (selectedRowKeys.length === 0) {
|
||||
setSelectAll(false);
|
||||
setIndeterminate(false);
|
||||
} else if (selectedRowKeys.length === props.dataSource.length) {
|
||||
setSelectAll(true);
|
||||
setIndeterminate(false);
|
||||
} else {
|
||||
setSelectAll(false);
|
||||
setIndeterminate(true);
|
||||
}
|
||||
}
|
||||
}, [rowSelection]);
|
||||
|
||||
const handleSelectAllChange = (e: any) => {
|
||||
if (e.target.checked) {
|
||||
// update selectedRowKeys
|
||||
rowSelection?.onChange(props.dataSource.map((record) => record[rowKey]));
|
||||
setSelectAll(true);
|
||||
setIndeterminate(false);
|
||||
} else {
|
||||
// update selectedRowKeys
|
||||
rowSelection?.onChange([]);
|
||||
setSelectAll(false);
|
||||
setIndeterminate(false);
|
||||
}
|
||||
};
|
||||
const renderHeaderPrefix = () => {
|
||||
if (expandable && rowSelection) {
|
||||
return (
|
||||
<div className="header-row-prefix-wrapper">
|
||||
<span style={{ marginRight: 5, padding: '0 14px' }}></span>
|
||||
<Checkbox
|
||||
onChange={handleSelectAllChange}
|
||||
indeterminate={indeterminate}
|
||||
checked={selectAll}
|
||||
></Checkbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (expandable) {
|
||||
return (
|
||||
<div className="header-row-prefix-wrapper">
|
||||
{_.isBoolean(expandable) ? (
|
||||
<Button type="text" size="small">
|
||||
<RightOutlined />
|
||||
</Button>
|
||||
) : (
|
||||
expandable
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (rowSelection) {
|
||||
return (
|
||||
<div className="header-row-prefix-wrapper">{<Checkbox></Checkbox>}</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderHeader = () => {
|
||||
return (
|
||||
<div className="header-row-wrapper">
|
||||
{renderHeaderPrefix()}
|
||||
<Row className="row">
|
||||
{React.Children.map(props.children, (child, i) => {
|
||||
const { props: columnProps } = child as any;
|
||||
const { title, align, span, headerStyle } =
|
||||
columnProps as SealColumnProps;
|
||||
if (React.isValidElement(child)) {
|
||||
return (
|
||||
<Col span={span}>
|
||||
<TableHeader
|
||||
title={title}
|
||||
style={headerStyle}
|
||||
firstCell={i === 0}
|
||||
lastCell={i === props.children.length - 1}
|
||||
></TableHeader>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
if (!props.dataSource.length) {
|
||||
return <Empty></Empty>;
|
||||
}
|
||||
return (
|
||||
<div className="seal-table-content">
|
||||
{props.dataSource.map((item, index) => {
|
||||
return (
|
||||
<TableRow
|
||||
record={item}
|
||||
rowIndex={index}
|
||||
columns={children}
|
||||
key={item[rowKey]}
|
||||
rowSelection={rowSelection}
|
||||
expandable={expandable}
|
||||
rowKey={rowKey}
|
||||
onExpand={onExpand}
|
||||
></TableRow>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div className="seal-table-container">
|
||||
{renderHeader()}
|
||||
{loading ? (
|
||||
<div className="spin">
|
||||
<Spin></Spin>
|
||||
</div>
|
||||
) : (
|
||||
renderContent()
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SealTable;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const RowContext = React.createContext({});
|
||||
|
||||
export default RowContext;
|
||||
@@ -0,0 +1,17 @@
|
||||
.cell {
|
||||
padding: var(--ant-table-cell-padding-block)
|
||||
var(--ant-table-cell-padding-inline);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
height: 70px;
|
||||
&-left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
&-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
&-center {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
.table-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding-inline: var(--ant-table-cell-padding-inline);
|
||||
border-right: 1px solid var(--ant-table-header-split-color);
|
||||
|
||||
&-last {
|
||||
border-right: none;
|
||||
}
|
||||
&-cell {
|
||||
font-weight: 600;
|
||||
}
|
||||
&-left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
&-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
&-center {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
.seal-table-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.header-row-wrapper {
|
||||
height: 40px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.header-row-prefix-wrapper {
|
||||
padding-left: var(--ant-table-cell-padding-inline);
|
||||
}
|
||||
.row {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.row-box {
|
||||
margin-bottom: 20px;
|
||||
border-radius: var(--ant-table-header-border-radius);
|
||||
overflow: hidden;
|
||||
}
|
||||
.expanded-row {
|
||||
background-color: var(--color-white-1);
|
||||
padding: 16px 20px;
|
||||
border: 1px solid var(--color-fill-1);
|
||||
border-top: 0;
|
||||
border-radius: 0 0 var(--ant-table-header-border-radius)
|
||||
var(--ant-table-header-border-radius);
|
||||
}
|
||||
.row-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
background-color: var(--color-fill-1);
|
||||
transition: all 0.2s ease;
|
||||
&:hover {
|
||||
background-color: var(--ant-table-row-hover-bg);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
&-selected {
|
||||
background-color: var(--ant-table-row-selected-bg);
|
||||
transition: all 0.2s ease;
|
||||
&:hover {
|
||||
background-color: var(--ant-table-row-selected-hover-bg);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
}
|
||||
.row-prefix-wrapper {
|
||||
padding-left: var(--ant-table-cell-padding-inline);
|
||||
}
|
||||
}
|
||||
.seal-table-row {
|
||||
flex: 1;
|
||||
}
|
||||
.spin {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface SealColumnProps {
|
||||
title: string;
|
||||
render?: (text: any, record: any) => React.ReactNode;
|
||||
dataIndex: string;
|
||||
width?: number;
|
||||
span: number;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
headerStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export interface TableHeaderProps {
|
||||
children?: React.ReactNode;
|
||||
title: string;
|
||||
style?: React.CSSProperties;
|
||||
firstCell?: boolean;
|
||||
lastCell?: boolean;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
}
|
||||
|
||||
export interface RowSelectionProps {
|
||||
selectedRowKeys: React.Key[];
|
||||
onChange: (selectedRowKeys: React.Key[]) => void;
|
||||
}
|
||||
export interface SealTableProps {
|
||||
rowSelection?: RowSelectionProps;
|
||||
children: React.ReactNode[];
|
||||
empty?: React.ReactNode;
|
||||
expandable?: React.ReactNode;
|
||||
dataSource: any[];
|
||||
loading?: boolean;
|
||||
onExpand?: (expanded: boolean, record: any) => void;
|
||||
rowKey: string;
|
||||
}
|
||||
|
||||
export interface RowContextProps {
|
||||
record: Record<string, any>;
|
||||
columns: React.ReactNode[];
|
||||
rowIndex: number;
|
||||
}
|
||||
@@ -15,6 +15,13 @@ html {
|
||||
--ant-color-fill-secondary: rgba(0, 0, 0, 0.06);
|
||||
--table-td-radius: 24px;
|
||||
--checkbox-border-radius: 4px;
|
||||
--ant-table-cell-padding-inline: 16px;
|
||||
--ant-table-cell-padding-block: 16px;
|
||||
--ant-table-header-border-radius: 16px;
|
||||
--ant-table-header-split-color: #f0f0f0;
|
||||
--ant-table-row-selected-bg: #f0fff6;
|
||||
--ant-table-row-selected-hover-bg: #d8f2e4;
|
||||
--ant-table-row-hover-bg: #e6e6e6;
|
||||
// --color-text-1: #000;
|
||||
|
||||
--seal-transition-func: cubic-bezier(0, 0, 1, 1);
|
||||
|
||||
@@ -86,6 +86,7 @@ export default (props: any) => {
|
||||
loading: false,
|
||||
setInitialState: null
|
||||
};
|
||||
console.log('initialInfo==========', initialInfo);
|
||||
const { initialState, loading, setInitialState } = initialInfo;
|
||||
|
||||
const userConfig = {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import SealTable from '@/components/seal-table';
|
||||
import SealColumn from '@/components/seal-table/components/seal-column';
|
||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||
|
||||
const Table = () => {
|
||||
const dataSource = [{ name: 'test' }, { name: 'test2' }];
|
||||
const rowSelection = useTableRowSelection();
|
||||
return (
|
||||
<SealTable
|
||||
dataSource={dataSource}
|
||||
rowKey="name"
|
||||
loading={false}
|
||||
rowSelection={rowSelection}
|
||||
expandable={true}
|
||||
>
|
||||
<SealColumn title="Name" dataIndex="name" key="name" span={12} />
|
||||
<SealColumn title="Status" dataIndex="status" key="status" span={12} />
|
||||
</SealTable>
|
||||
);
|
||||
};
|
||||
|
||||
export default Table;
|
||||
@@ -4,8 +4,14 @@ import { Tabs } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import GPUs from './components/gpus';
|
||||
import Nodes from './components/nodes';
|
||||
import Test from './components/test';
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: 'test',
|
||||
label: 'Test',
|
||||
children: <Test />
|
||||
},
|
||||
{
|
||||
key: 'nodes',
|
||||
label: 'Nodes',
|
||||
@@ -18,7 +24,7 @@ const items: TabsProps['items'] = [
|
||||
}
|
||||
];
|
||||
const Resources = () => {
|
||||
const [activeKey, setActiveKey] = useState('nodes');
|
||||
const [activeKey, setActiveKey] = useState('test');
|
||||
|
||||
const handleChangeTab = (key: string) => {
|
||||
setActiveKey(key);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import PageTools from '@/components/page-tools';
|
||||
import SealTable from '@/components/seal-table';
|
||||
import SealColumn from '@/components/seal-table/components/seal-column';
|
||||
import { PageAction } from '@/config';
|
||||
import type { PageActionType } from '@/config/types';
|
||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||
@@ -208,11 +210,12 @@ const Models: React.FC = () => {
|
||||
</Space>
|
||||
}
|
||||
></PageTools>
|
||||
<Table
|
||||
<SealTable
|
||||
dataSource={dataSource}
|
||||
rowSelection={rowSelection}
|
||||
loading={loading}
|
||||
rowKey="id"
|
||||
expandable={true}
|
||||
onChange={handleTableChange}
|
||||
pagination={{
|
||||
showSizeChanger: true,
|
||||
@@ -224,11 +227,12 @@ const Models: React.FC = () => {
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
>
|
||||
<Column
|
||||
<SealColumn
|
||||
title="Model Name"
|
||||
dataIndex="name"
|
||||
key="name"
|
||||
width={400}
|
||||
span={8}
|
||||
render={(text, record) => {
|
||||
return (
|
||||
<>
|
||||
@@ -243,7 +247,8 @@ const Models: React.FC = () => {
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
<SealColumn
|
||||
span={8}
|
||||
title="Create Time"
|
||||
dataIndex="created_at"
|
||||
key="createTime"
|
||||
@@ -255,7 +260,8 @@ const Models: React.FC = () => {
|
||||
return dayjs(val).format('YYYY-MM-DD HH:mm:ss');
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
<SealColumn
|
||||
span={8}
|
||||
title="Operation"
|
||||
key="operation"
|
||||
render={(text, record) => {
|
||||
@@ -282,7 +288,7 @@ const Models: React.FC = () => {
|
||||
) : null;
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
</SealTable>
|
||||
</PageContainer>
|
||||
<AddModal
|
||||
open={openAddModal}
|
||||
|
||||
@@ -243,7 +243,7 @@ const Models: React.FC = () => {
|
||||
<Column
|
||||
title="Operation"
|
||||
key="operation"
|
||||
render={(text, record) => {
|
||||
render={(text, record: ListItem) => {
|
||||
return (
|
||||
<Space>
|
||||
<Tooltip title="编辑">
|
||||
|
||||
@@ -7,6 +7,7 @@ export const requestConfig: RequestConfig = {
|
||||
console.log('errorThrower+++++++++++++++', res);
|
||||
},
|
||||
errorHandler: (error: any, opts: any) => {
|
||||
if (opts?.skipErrorHandler) throw error;
|
||||
const { message: errorMessage, response } = error;
|
||||
const errMsg = response?.data?.message || errorMessage;
|
||||
message.error(errMsg);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { request } from '@umijs/max';
|
||||
|
||||
export async function queryCurrentUserState(opts?: Record<string, any>) {
|
||||
return request(`/users/me`, {
|
||||
method: 'GET',
|
||||
...opts
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user