Files
scrm.antd/src/pages/DepartmentsList/index.tsx
2023-04-24 13:43:36 +08:00

419 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { SearchBarPlugin } from '@/components/SearchBarPlugin';
import { post } from '@/services/ajax';
import { PageContainer } from '@ant-design/pro-components';
import {
App,
Button,
Col,
Drawer,
Form,
Input,
Modal,
Pagination,
Row,
Spin,
Table,
Tree,
} from 'antd';
import { stringify } from 'qs';
import React, { useEffect, useState } from 'react';
import { IStaffsItem } from '../ChatLogs/ChatLogsType';
import { DepartmentMembersDetail } from './components/DepartmentMemberDetail';
import styles from './index.module.scss';
interface IDepartment {
children: null | IDepartment[];
department_leader: string;
id: number;
name: string;
parent_id: number;
sort: number;
}
interface IStaffsData {
count: number;
data?: IStaffsItem[];
}
type Param = {
curr_page: number;
page_count: number;
dep_id: number;
name?: string;
position?: string;
telephone?: string;
mobile?: string;
};
const DepartmentsList: React.FC = () => {
const [param] = useState<Param>({
curr_page: 1,
page_count: 20,
dep_id: 0,
});
const { notification } = App.useApp();
const [departmentID, setDepartmentsID] = useState<number>(0);
const [departmentsList, setDepartmentsList] = useState<IDepartment[]>([]);
const [staffsData, setStaffsData] = useState<IStaffsData>({ count: 0, data: [] });
const [loadingL, setLoadingL] = useState(false);
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
const [record, setRecord] = useState<IStaffsItem>();
const getStaffsList = () => {
setLoading(true);
post({ url: '/Staffs/List', data: stringify(param) }).then((res) => {
setLoading(false);
if (res.err_code == 0) {
if (!Array.isArray(res.data)) {
res.data = [];
}
setStaffsData(res as IStaffsData);
}
});
};
const getDepartmentsList = () => {
setLoadingL(true);
post({ url: '/Departments/List' }).then((res) => {
setLoadingL(false);
if (res.err_code == 0) {
if (Array.isArray(res.data)) {
setDepartmentsList(res.data);
if (res.data.length) {
param.dep_id = res.data[0].id;
setDepartmentsID(param.dep_id);
getStaffsList();
}
}
}
});
};
const page = (page: number) => {
param.curr_page = page;
getStaffsList();
};
useEffect(() => {
getDepartmentsList();
}, []);
// const [open, setOpen] = useState(false);
// const [popOpen, setPopOpen] = useState(-1);
const [syncLoading, setSyncLoading] = useState(false);
const [syncOpen, setSyncOpen] = useState('');
const syncDepartments = () => {
setSyncLoading(false);
setSyncOpen('dep');
};
const syncStaffs = () => {
setSyncLoading(false);
setSyncOpen('staff');
};
const syncDepOrStaff = () => {
if (syncLoading) return;
setSyncLoading(true);
if (syncOpen == 'dep') {
post({ url: '/Sync/Departments' }).then((res) => {
setSyncLoading(false);
if (res.err_code == 0) {
notification.success({
message: res.err_msg,
});
setSyncOpen('');
getDepartmentsList();
}
});
} else {
post({ url: '/Sync/Staffs' }).then((res) => {
setSyncLoading(false);
if (res.err_code == 0) {
notification.success({
message: res.err_msg,
});
setSyncOpen('');
getStaffsList();
}
});
}
};
return (
<PageContainer>
<div style={{ display: 'flex' }}>
<div
style={{
width: 240,
flexShrink: 0,
minHeight: 'calc(100vh - 55px - 60px - 96px)',
maxHeight: 'calc(100vh - 55px - 60px)',
overflow: 'auto',
marginRight: 12,
background: '#fff',
position: 'sticky',
top: 64,
padding: '12px 0',
}}
>
<Spin spinning={loadingL} style={{ display: 'block' }}>
{departmentsList.length ? (
<Tree
className={'department-tree'}
blockNode
selectedKeys={[departmentID]}
defaultExpandAll
treeData={departmentsList as any}
fieldNames={{ title: 'name', key: 'id' }}
onSelect={(selectedKeys) => {
if (selectedKeys.length) {
setDepartmentsID(Number(selectedKeys[0]));
param.dep_id = Number(selectedKeys[0]);
page(1);
}
}}
titleRender={(nodeData: any) => {
// console.log(nodeData);
return (
<div className={styles.departmentItem}>
<div className={styles.name} title={nodeData.name}>
{nodeData.name}
</div>
{/* <div className={styles.btnsBox}>
<FormOutlined
title="修改"
onClick={(e) => {
e.stopPropagation();
setOpen(true);
}}
className={styles.edit}
/>
<Popconfirm
title="确认删除?"
open={popOpen == nodeData.id}
onCancel={(e) => {
setPopOpen(-1);
e?.stopPropagation();
}}
onConfirm={(e) => {
e?.stopPropagation();
console.log(nodeData.id);
}}
>
<DeleteOutlined
title="删除"
onClick={(e) => {
e.stopPropagation();
setPopOpen(nodeData.id);
}}
className={styles.del}
/>
</Popconfirm>
</div> */}
</div>
);
}}
/>
) : null}
</Spin>
</div>
<Modal
title="系统提示"
open={!!syncOpen}
onOk={syncDepOrStaff}
onCancel={() => setSyncOpen('')}
centered
width={300}
>
<Spin spinning={syncLoading}>
<div>{syncOpen == 'dep' ? '确定同步部门?' : '确定同步员工?'}</div>
</Spin>
</Modal>
{/* <Modal
open={open}
title="修改部门"
onCancel={() => setOpen(false)}
centered
onOk={() => {}}
>
<Form>
<Form.Item label="名称">
<Input type="text"></Input>
</Form.Item>
</Form>
</Modal> */}
<div style={{ flexGrow: 1, minWidth: 0 }}>
<SearchBarPlugin
body={
<Form autoComplete="off">
<Row gutter={{ xs: 0, sm: 16 }}>
<Col xs={24} lg={12} xl={8}>
<Form.Item label={<span style={{ textIndent: '1em' }}></span>}>
<Input
autoComplete="off"
onChange={(e) => {
param.name = e.target.value.trim();
}}
allowClear
onPressEnter={() => page(1)}
/>
</Form.Item>
</Col>
<Col xs={24} lg={12} xl={8}>
<Form.Item label={<span style={{ textIndent: '1em' }}></span>}>
<Input
autoComplete="off"
onChange={(e) => {
param.position = e.target.value.trim();
}}
allowClear
onPressEnter={() => page(1)}
/>
</Form.Item>
</Col>
<Col xs={24} lg={12} xl={8}>
<Form.Item label="手机号">
<Input
autoComplete="off"
onChange={(e) => {
param.mobile = e.target.value.trim();
}}
allowClear
onPressEnter={() => page(1)}
/>
</Form.Item>
</Col>
</Row>
</Form>
}
footer={
<Row justify={'center'}>
<Button
type="primary"
onClick={() => {
page(1);
}}
style={{ marginRight: 12 }}
>
</Button>
<Button
type="primary"
onClick={() => {
syncDepartments();
}}
style={{ marginRight: 12 }}
>
</Button>
<Button
type="primary"
onClick={() => {
syncStaffs();
}}
>
</Button>
</Row>
}
/>
<Table
tableLayout="fixed"
size="middle"
dataSource={staffsData.data}
style={{ padding: 16, borderRadius: 6, background: '#fff', marginTop: 16 }}
pagination={false}
bordered={true}
rowKey={'user_id'}
loading={loading}
>
<Table.Column
title="姓名"
dataIndex={'name'}
render={(value, record: IStaffsItem) => {
return (
<div
onClick={() => {
setRecord(record);
setOpen(true);
}}
style={{ color: '#1890ff', cursor: 'pointer' }}
>
<span
style={{
display: 'inline-block',
marginRight: record.isleader == 1 ? 4 : 0,
}}
>
{value}
</span>
{record?.isleader == 1 ? (
<span
style={{
color: '#999',
fontSize: 12,
border: '1px solid #ddd',
borderRadius: 4,
padding: '2px 4px',
}}
>
</span>
) : null}
</div>
);
}}
/>
<Table.Column title="职务" width={160} dataIndex={'position'} />
<Table.Column
title="部门"
dataIndex={'dep_name'}
render={(val) => {
return <>{val.join('')}</>;
}}
/>
<Table.Column title="手机号" width={160} dataIndex={'mobile'} />
<Table.Column title="企业邮箱" dataIndex={'biz_mail'} />
</Table>
<Drawer title="成员详情" open={open} onClose={() => setOpen(false)} width={800}>
<DepartmentMembersDetail record={record as IStaffsItem} />
</Drawer>
<Pagination
style={{
background: '#fff',
borderRadius: 6,
marginTop: 16,
padding: 16,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
current={param.curr_page}
pageSize={param.page_count}
total={staffsData.count}
pageSizeOptions={[10, 20, 50, 100]}
onShowSizeChange={(current, size) => {
param.page_count = size;
// setParam({ ...param });
page(1);
}}
showTotal={(total) => {
return <span style={{ lineHeight: 1 }}>{total}</span>;
}}
onChange={(curr) => {
page(curr);
}}
/>
</div>
</div>
</PageContainer>
);
};
export default DepartmentsList;