feat(project): base smatec's frontend
This commit is contained in:
258
src/pages/Manager/User/index.tsx
Normal file
258
src/pages/Manager/User/index.tsx
Normal file
@@ -0,0 +1,258 @@
|
||||
import TreeGroup from '@/components/shared/TreeGroup';
|
||||
import { DEFAULT_PAGE_SIZE } from '@/constants';
|
||||
import {
|
||||
apiQueryUsers,
|
||||
apiQueryUsersByGroup,
|
||||
} from '@/services/master/UserController';
|
||||
import {
|
||||
ActionType,
|
||||
ProCard,
|
||||
ProColumns,
|
||||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { FormattedMessage, useIntl } from '@umijs/max';
|
||||
import { Grid } from 'antd';
|
||||
import message from 'antd/es/message';
|
||||
import Paragraph from 'antd/lib/typography/Paragraph';
|
||||
import { useRef, useState } from 'react';
|
||||
import CreateUser from './components/CreateUser';
|
||||
|
||||
const ManagerUserPage = () => {
|
||||
const { useBreakpoint } = Grid;
|
||||
const intl = useIntl();
|
||||
const screens = useBreakpoint();
|
||||
const actionRef = useRef<ActionType | null>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const [selectedRowsState, setSelectedRowsState] = useState<
|
||||
MasterModel.ProfileResponse[]
|
||||
>([]);
|
||||
const [groupCheckedKeys, setGroupCheckedKeys] = useState<
|
||||
string | string[] | null
|
||||
>(null);
|
||||
|
||||
const columns: ProColumns<MasterModel.ProfileResponse>[] = [
|
||||
{
|
||||
key: 'email',
|
||||
title: (
|
||||
<FormattedMessage id="master.users.email" defaultMessage="Email" />
|
||||
),
|
||||
tip: intl.formatMessage({
|
||||
id: 'master.users.email.tip',
|
||||
defaultMessage: 'The email is the unique key',
|
||||
}),
|
||||
dataIndex: 'email',
|
||||
render: (_, record) => (
|
||||
<Paragraph
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
verticalAlign: 'middle',
|
||||
display: 'inline-block',
|
||||
}}
|
||||
copyable
|
||||
>
|
||||
{record?.email}
|
||||
</Paragraph>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
key: 'phone_number',
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="master.users.phone_number"
|
||||
defaultMessage="Phone number"
|
||||
/>
|
||||
),
|
||||
tip: intl.formatMessage({
|
||||
id: 'master.users.phone_number.tip',
|
||||
defaultMessage: 'The phone number is the unique key',
|
||||
}),
|
||||
responsive: ['lg', 'md'],
|
||||
dataIndex: ['metadata', 'phone_number'],
|
||||
render: (_, record) =>
|
||||
record?.metadata?.phone_number ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
verticalAlign: 'middle',
|
||||
display: 'inline-block',
|
||||
}}
|
||||
copyable
|
||||
>
|
||||
{record?.metadata?.phone_number}
|
||||
</Paragraph>
|
||||
) : (
|
||||
'-'
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
key: 'user_type',
|
||||
hideInSearch: true,
|
||||
title: <FormattedMessage id="master.users.role" defaultMessage="Role" />,
|
||||
tip: intl.formatMessage({
|
||||
id: 'master.users.role.tip',
|
||||
defaultMessage: 'The role is the unique key',
|
||||
}),
|
||||
dataIndex: ['metadata', 'user_type'],
|
||||
render: (_, record) => record?.metadata?.user_type || '...',
|
||||
},
|
||||
|
||||
{
|
||||
title: (
|
||||
<FormattedMessage id="common.actions" defaultMessage="Operating" />
|
||||
),
|
||||
hideInSearch: true,
|
||||
render: () => {
|
||||
return (
|
||||
<>
|
||||
{/* <PermissionButton
|
||||
user={record}
|
||||
title={intl.formatMessage({
|
||||
id: 'master.users.assign',
|
||||
defaultMessage: 'Assgin',
|
||||
})}
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
<ProCard split={screens.md ? 'vertical' : 'horizontal'}>
|
||||
<ProCard colSpan={{ xs: 24, sm: 24, md: 6, lg: 6, xl: 6 }}>
|
||||
<TreeGroup
|
||||
disable={isLoading}
|
||||
multiple={true}
|
||||
groupIds={groupCheckedKeys}
|
||||
onSelected={(value: string | string[] | null) => {
|
||||
setGroupCheckedKeys(value);
|
||||
if (actionRef.current) {
|
||||
actionRef.current.reload();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</ProCard>
|
||||
<ProCard colSpan={{ xs: 24, sm: 24, md: 18, lg: 18, xl: 18 }}>
|
||||
<ProTable<MasterModel.ProfileResponse>
|
||||
columns={columns}
|
||||
tableLayout="auto"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
search={{
|
||||
layout: 'vertical',
|
||||
defaultCollapsed: false,
|
||||
}}
|
||||
dateFormatter="string"
|
||||
rowSelection={{
|
||||
selectedRowKeys: selectedRowsState.map((row) => row.id!),
|
||||
onChange: (
|
||||
_: React.Key[],
|
||||
selectedRows: MasterModel.ProfileResponse[],
|
||||
) => {
|
||||
setSelectedRowsState(selectedRows);
|
||||
},
|
||||
}}
|
||||
pagination={{
|
||||
defaultPageSize: DEFAULT_PAGE_SIZE * 2,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ['10', '15', '20'],
|
||||
showTotal: (total, range) =>
|
||||
`${range[0]}-${range[1]}
|
||||
${intl.formatMessage({
|
||||
id: 'common.paginations.of',
|
||||
defaultMessage: 'of',
|
||||
})}
|
||||
${total} ${intl.formatMessage({
|
||||
id: 'master.users.table.pagination',
|
||||
defaultMessage: 'users',
|
||||
})}`,
|
||||
}}
|
||||
request={async (params = {}) => {
|
||||
const { current = 1, pageSize, email, phone_number } = params;
|
||||
const size = pageSize || DEFAULT_PAGE_SIZE * 2;
|
||||
const offset = current === 1 ? 0 : (current - 1) * size;
|
||||
setIsLoading(true);
|
||||
// If groups are checked, use queryUsersByGroup
|
||||
if (groupCheckedKeys && groupCheckedKeys.length > 0) {
|
||||
// Ensure groupCheckedKeys is an array
|
||||
const groupIdsArray = Array.isArray(groupCheckedKeys)
|
||||
? groupCheckedKeys.join(',')
|
||||
: groupCheckedKeys;
|
||||
|
||||
const userByGroupResponses = await apiQueryUsersByGroup(
|
||||
groupIdsArray,
|
||||
);
|
||||
let users = userByGroupResponses.users || [];
|
||||
// Apply filters
|
||||
if (email) {
|
||||
users = users.filter((user: MasterModel.ProfileResponse) =>
|
||||
user.email?.includes(email),
|
||||
);
|
||||
}
|
||||
if (phone_number) {
|
||||
users = users.filter((user: MasterModel.ProfileResponse) =>
|
||||
user.metadata?.phone_number?.includes(phone_number),
|
||||
);
|
||||
}
|
||||
|
||||
const total = users.length;
|
||||
const paginatedUsers = users.slice(offset, offset + size);
|
||||
setIsLoading(false);
|
||||
return {
|
||||
data: paginatedUsers,
|
||||
success: true,
|
||||
total: total,
|
||||
};
|
||||
} else {
|
||||
// Use regular queryUsers API
|
||||
const metadata: Partial<MasterModel.ProfileMetadata> = {};
|
||||
if (phone_number) metadata.phone_number = phone_number;
|
||||
|
||||
const query: MasterModel.SearchUserPaginationBody = {
|
||||
offset: offset,
|
||||
limit: size,
|
||||
order: 'name',
|
||||
dir: 'asc',
|
||||
};
|
||||
if (email) query.email = email;
|
||||
if (Object.keys(metadata).length > 0) query.metadata = metadata;
|
||||
|
||||
const response = await apiQueryUsers(query);
|
||||
setIsLoading(false);
|
||||
return {
|
||||
data: response.users,
|
||||
success: true,
|
||||
total: response.total,
|
||||
};
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
search: false,
|
||||
setting: false,
|
||||
density: false,
|
||||
reload: true,
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<CreateUser
|
||||
message={messageApi}
|
||||
onSuccess={(isSuccess) => {
|
||||
if (isSuccess) {
|
||||
actionRef.current?.reload();
|
||||
}
|
||||
}}
|
||||
key="create-user"
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManagerUserPage;
|
||||
Reference in New Issue
Block a user