621 lines
23 KiB
TypeScript
621 lines
23 KiB
TypeScript
import styles from '@/page/Home/User/index.module.scss'
|
||
import { useEffect, useState, useRef } from "react";
|
||
import Operation from '@/components/Operation';
|
||
import { Button, Input, Table, Pagination, Modal, message, Select } from "antd";
|
||
import { ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons';
|
||
import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList, PostUserImport, GetSubDpList, PutUserBth } from '@/api/Home/User';
|
||
import * as CryptoJS from 'crypto-js';
|
||
import ImageUrl from '@/utils/package/imageUrl';
|
||
import { storage } from '@/utils';
|
||
import StupWizard from '@/components/StupWizard';
|
||
const { Column } = Table
|
||
const { confirm } = Modal;
|
||
const { exec } = require('child_process');
|
||
const fs = require('fs').promises;
|
||
const User: React.FC = () => {
|
||
const stupWizardRef = useRef<any>();
|
||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||
const [isCreateUser, setIsCreateUser] = useState<'add' | 'batch' | 'edit'>();
|
||
const [list, setList] = useState({
|
||
data: [],
|
||
searchKeywod: '',
|
||
total: 0,
|
||
pageIndex: 1,
|
||
pageSize: 14,
|
||
})
|
||
const [roleList, setRoleList] = useState([])
|
||
const [addUserModal, setAddUserModal] = useState(false)
|
||
const [addUserFrom, setAddUserFrom] = useState({
|
||
Id: "",
|
||
Account: "",
|
||
RoleId: null,
|
||
Pwd: "",
|
||
UserName: "",
|
||
subject: null,
|
||
year: "",
|
||
})
|
||
const [changeUserPawModal, setChangeUserPawModal] = useState(false)
|
||
const [changeImportModal, setChangeImportModal] = useState(false)
|
||
const [changeUserPawFrom, setChangeUserPawFrom] = useState({
|
||
Pwd: "",
|
||
newPwd: '',
|
||
})
|
||
const [deleteUserPawModal, setDeleteUserPawModal] = useState(false)
|
||
const [subjectList, setSubjectList] = useState<any>([]);
|
||
useEffect(() => {
|
||
getSubDpList()
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
getUserList()
|
||
}, [list.pageIndex, list.pageSize]);
|
||
|
||
const getUserList = async (): Promise<void> => {
|
||
await GetUserList({
|
||
pageIndex: list.pageIndex,
|
||
pageSize: list.pageSize,
|
||
searchKeywod: list.searchKeywod,
|
||
}).then(res => {
|
||
if (res.code === 200) {
|
||
setList({
|
||
...list,
|
||
total: res.data.total,
|
||
data: res.data.items.map((item: any) => {
|
||
return {
|
||
...item,
|
||
key: item.id,
|
||
}
|
||
}),
|
||
})
|
||
setSelectedRowKeys([])
|
||
}
|
||
})
|
||
}
|
||
|
||
const getRoleDpList = async (callBack: Function): Promise<void> => {
|
||
await GetRoleDpList().then(res => {
|
||
if (res.code === 200) {
|
||
setRoleList(res.data.map((item: any) => {
|
||
return {
|
||
...item,
|
||
value: item.id,
|
||
label: item.roleName
|
||
}
|
||
}))
|
||
callBack(true)
|
||
}
|
||
})
|
||
}
|
||
const fileUpLoad = async (data: { url: string, content: string, fileName: string }): Promise<void> => {
|
||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||
try {
|
||
const response = await fetch(data.url);
|
||
const arrayBuffer = await response.arrayBuffer();
|
||
const buffer = Buffer.from(arrayBuffer);
|
||
await fs.writeFile(`${setting.shareFilesPath}\\${data.fileName}`, buffer, {});
|
||
setChangeImportModal(false)
|
||
confirm({
|
||
title: '提示',
|
||
icon: <ExclamationCircleFilled />,
|
||
content: data.content,
|
||
centered: true,
|
||
okText: '打开文件夹',
|
||
cancelText: '关闭',
|
||
async onOk() {
|
||
await fs.access(setting.shareFilesPath, fs.constants.F_OK);
|
||
if (process.platform === 'win32') {
|
||
exec(`explorer "${setting.shareFilesPath}"`);
|
||
} else if (process.platform === 'darwin') {
|
||
exec(`open "${setting.shareFilesPath}"`);
|
||
}
|
||
},
|
||
onCancel() {
|
||
}
|
||
})
|
||
} catch (error: any) {
|
||
if (error.code === 'ENOENT') {
|
||
message.error({
|
||
content: <div>文件夹不存在 <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
||
stupWizardRef.current.changeModal(4)
|
||
}}>前往设置</span></div>
|
||
})
|
||
return
|
||
} else {
|
||
message.error(error)
|
||
}
|
||
}
|
||
}
|
||
const getSubDpList = async (): Promise<void> => {
|
||
await GetSubDpList().then(res => {
|
||
if (res.code === 200) {
|
||
setSubjectList(res.data.map((item: any) => { return { value: item.value, label: item.name } }))
|
||
}
|
||
})
|
||
}
|
||
return (
|
||
<>
|
||
<div className={styles.user}>
|
||
<div className={styles.userOperation}>
|
||
<Operation></Operation>
|
||
</div>
|
||
<div className={styles.userBtns}>
|
||
<div className={`${styles.userBtnsLeft} drag`}>
|
||
<Button type="primary"
|
||
onClick={() => {
|
||
getRoleDpList((bool: boolean) => {
|
||
if (bool) {
|
||
setIsCreateUser('add')
|
||
setAddUserFrom({
|
||
Id: "",
|
||
Account: "",
|
||
RoleId: null,
|
||
Pwd: "",
|
||
UserName: "",
|
||
subject: null,
|
||
year: "",
|
||
})
|
||
setAddUserModal(true)
|
||
}
|
||
})
|
||
}}
|
||
icon={<img src={ImageUrl.icon8} alt="" />}
|
||
className='m-ant-btn'>
|
||
添加用户
|
||
</Button>
|
||
<Button type="primary"
|
||
onClick={() => {
|
||
setChangeImportModal(true)
|
||
}}
|
||
className='m-ant-btn'>
|
||
批量导入用户
|
||
</Button>
|
||
<Button type="primary"
|
||
onClick={() => {
|
||
if (selectedRowKeys.length) {
|
||
getRoleDpList((bool: boolean) => {
|
||
if (bool) {
|
||
setIsCreateUser('batch')
|
||
setAddUserFrom({
|
||
Id: "",
|
||
Account: "",
|
||
RoleId: null,
|
||
Pwd: "",
|
||
UserName: "",
|
||
subject: null,
|
||
year: "",
|
||
})
|
||
setAddUserModal(true)
|
||
}
|
||
})
|
||
} else {
|
||
message.error('请选择需要修改的用户!')
|
||
}
|
||
}}
|
||
className='m-ant-btn'>
|
||
批量修改用户信息
|
||
</Button>
|
||
<Button type="primary"
|
||
icon={<img src={ImageUrl.icon21} alt="" />}
|
||
className={styles.userBtnsDel}
|
||
onClick={() => {
|
||
if (selectedRowKeys.length) {
|
||
setDeleteUserPawModal(true)
|
||
} else {
|
||
message.error('请选择需要删除的用户!')
|
||
}
|
||
}}
|
||
>
|
||
删除用户
|
||
</Button>
|
||
</div>
|
||
<div className={`${styles.userBtnsRight} drag`}>
|
||
<Input
|
||
placeholder="请输入用户名或账号"
|
||
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
||
value={list.searchKeywod}
|
||
onChange={(e) => {
|
||
setList({
|
||
...list,
|
||
searchKeywod: e.target.value,
|
||
})
|
||
}}
|
||
/>
|
||
<Button className='m-border-ant-button' onClick={() => {
|
||
if (list.pageIndex === 1) {
|
||
getUserList()
|
||
} else {
|
||
setList({
|
||
...list,
|
||
pageIndex: 1
|
||
})
|
||
}
|
||
}}>查询</Button>
|
||
</div>
|
||
</div>
|
||
<div className={`${styles.userContent} drag`}>
|
||
<Table
|
||
size={'small'}
|
||
rowSelection={{
|
||
selectedRowKeys,
|
||
onChange: (newSelectedRowKeys: React.Key[]) => {
|
||
setSelectedRowKeys(newSelectedRowKeys);
|
||
}
|
||
}}
|
||
dataSource={list.data}
|
||
pagination={false}
|
||
scroll={{ y: '70vh' }}
|
||
className={styles.userContentTable}
|
||
>
|
||
<Column title="姓名" dataIndex="userName" key="userName" />
|
||
<Column title="账号" dataIndex="account" key="account" />
|
||
<Column title="角色" dataIndex="roleName" key="roleName" />
|
||
<Column title="在线状态" render={(item) => (
|
||
<>
|
||
<div style={{ color: item.isOnline ? '#02B188' : 'rgb(221 11 11)' }}>{item.isOnline ? '在线' : '离线'}</div>
|
||
</>
|
||
)} />
|
||
<Column title="届" dataIndex="year" key="year" />
|
||
<Column title="学科" render={(item) => (
|
||
<>
|
||
<div>{subjectList.find((subject: any) => subject.value === item.subject)?.label}</div>
|
||
</>
|
||
)} />
|
||
<Column title="操作" width={200} render={(item) => (
|
||
<>
|
||
<Button
|
||
type="primary"
|
||
style={{ backgroundColor: '#0085FF30', marginRight: '14px' }}
|
||
size={'small'}
|
||
onClick={() => {
|
||
getRoleDpList((bool: boolean) => {
|
||
if (bool) {
|
||
setIsCreateUser('edit')
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
Id: item.id,
|
||
Account: item.account,
|
||
RoleId: item.roleId,
|
||
UserName: item.userName,
|
||
subject: item.subject,
|
||
year: item.year,
|
||
})
|
||
setAddUserModal(true)
|
||
}
|
||
})
|
||
}}>编辑</Button>
|
||
<Button
|
||
type="primary"
|
||
style={{ backgroundColor: '#715AFF40', marginRight: '14px' }}
|
||
size={'small'}
|
||
onClick={() => {
|
||
setChangeUserPawFrom({
|
||
Pwd: "",
|
||
newPwd: '',
|
||
})
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
Id: item.id,
|
||
Account: item.account,
|
||
RoleId: item.roleId,
|
||
UserName: item.userName,
|
||
})
|
||
setChangeUserPawModal(true)
|
||
}}>更改密码</Button>
|
||
</>
|
||
)} />
|
||
</Table>
|
||
<div className={styles.userContentPagination}>
|
||
<span>共{list.total}项数据</span>
|
||
<Pagination size="small" total={list.total} onChange={(page, pageSize) => {
|
||
setList({
|
||
...list,
|
||
pageIndex: page,
|
||
pageSize: pageSize
|
||
})
|
||
}} showSizeChanger pageSizeOptions={[10, 14, 20, 30, 40, 50, 100]} pageSize={list.pageSize} current={list.pageIndex} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<Modal title={isCreateUser === 'add' ? '添加用户' : isCreateUser === 'edit' ? '编辑用户' : '批量修改用户信息'} open={addUserModal} footer={null} closable={false} centered width={'500px'}>
|
||
<div>
|
||
<div className={styles.addUserModal}>
|
||
{isCreateUser !== 'batch' ? <div>
|
||
<span>账号:</span>
|
||
<Input
|
||
style={{ flexGrow: 1 }}
|
||
placeholder="请输入账号"
|
||
maxLength={30}
|
||
showCount={true}
|
||
value={addUserFrom.Account}
|
||
onChange={(e) => {
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
Account: e.target.value,
|
||
});
|
||
}}
|
||
/>
|
||
</div> : null}
|
||
{isCreateUser !== 'batch' ? <div>
|
||
<span>角色:</span>
|
||
<Select
|
||
placeholder='请选择角色'
|
||
options={roleList}
|
||
style={{ flexGrow: 1 }}
|
||
value={addUserFrom.RoleId} onChange={(e) => {
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
RoleId: e
|
||
});
|
||
}} />;
|
||
</div> : null}
|
||
{isCreateUser === 'add' ? <div>
|
||
<span>密码:</span>
|
||
<Input.Password
|
||
placeholder="请输入密码"
|
||
style={{ flexGrow: 1 }}
|
||
value={addUserFrom.Pwd}
|
||
onChange={(e) => {
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
Pwd: e.target.value,
|
||
});
|
||
}}
|
||
/>
|
||
</div> : null}
|
||
{isCreateUser !== 'batch' ? <div>
|
||
<span>用户名称:</span>
|
||
<Input
|
||
placeholder="请输入用户名称"
|
||
style={{ flexGrow: 1 }}
|
||
value={addUserFrom.UserName}
|
||
onChange={(e) => {
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
UserName: e.target.value,
|
||
});
|
||
}}
|
||
/>
|
||
</div> : null}
|
||
<div>
|
||
<span>届:</span>
|
||
<Input
|
||
placeholder="请输入届"
|
||
value={addUserFrom.year}
|
||
onChange={(e) => {
|
||
const regex = /^[0-9]*$/;
|
||
if (regex.test(e.target.value)) {
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
year: e.target.value
|
||
});
|
||
}
|
||
}}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<span>学科:</span>
|
||
<Select
|
||
placeholder='请选择学科'
|
||
style={{ flexGrow: 1 }}
|
||
options={subjectList}
|
||
value={addUserFrom.subject} onChange={(e) => {
|
||
setAddUserFrom({
|
||
...addUserFrom,
|
||
subject: e
|
||
});
|
||
}} />
|
||
</div>
|
||
</div>
|
||
<div style={{
|
||
display: 'flex', justifyContent: 'center'
|
||
}}>
|
||
<Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }} onClick={() => setAddUserModal(false)}>取消</Button>
|
||
<Button type="primary" className='m-ant-btn' onClick={async () => {
|
||
if (!addUserFrom.Account && isCreateUser !== 'batch') {
|
||
return message.error('请输入账号!')
|
||
}
|
||
if (!addUserFrom.RoleId && isCreateUser !== 'batch') {
|
||
return message.error('请选择角色!')
|
||
}
|
||
if (!addUserFrom.Pwd && isCreateUser === 'add') {
|
||
return message.error('请输入密码!')
|
||
}
|
||
if (!addUserFrom.UserName && isCreateUser !== 'batch') {
|
||
return message.error('请输入用户名称!')
|
||
}
|
||
if (!addUserFrom.year) {
|
||
return message.error('请输入届!')
|
||
}
|
||
if (addUserFrom.subject === null) {
|
||
return message.error('请选择学科!')
|
||
}
|
||
if (isCreateUser === 'add') {
|
||
await PostUser({
|
||
...addUserFrom,
|
||
Pwd: CryptoJS.MD5(addUserFrom.Pwd).toString(CryptoJS.enc.Hex)
|
||
}).then(res => {
|
||
if (res.code === 200) {
|
||
setAddUserModal(false)
|
||
res.data ? message.success('添加成功!') : message.error('添加失败!')
|
||
}
|
||
})
|
||
} else if (isCreateUser === 'edit') {
|
||
await PutUser({
|
||
Id: addUserFrom.Id,
|
||
Account: addUserFrom.Account,
|
||
RoleId: addUserFrom.RoleId,
|
||
UserName: addUserFrom.UserName,
|
||
subject: addUserFrom.subject,
|
||
year: addUserFrom.year,
|
||
}).then(res => {
|
||
if (res.code === 200) {
|
||
setAddUserModal(false)
|
||
res.data ? message.success('修改成功!') : message.error('修改失败!')
|
||
}
|
||
})
|
||
} else {
|
||
const param = selectedRowKeys.map((item: any) => {
|
||
return {
|
||
id: item,
|
||
subject: addUserFrom.subject,
|
||
year: addUserFrom.year
|
||
}
|
||
})
|
||
await PutUserBth(param).then(res => {
|
||
if (res.code === 200) {
|
||
setAddUserModal(false)
|
||
res.data ? message.success('修改成功!') : message.error('修改失败!')
|
||
}
|
||
})
|
||
}
|
||
await getUserList()
|
||
}}>{isCreateUser === 'add' ? '添加' : '修改'}</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
<Modal title='更改密码' open={changeUserPawModal} footer={null} closable={false} centered width={'500px'}>
|
||
<div>
|
||
<div className={styles.addUserModal}>
|
||
<div>
|
||
<span>新密码:</span>
|
||
<Input.Password
|
||
placeholder="请输入新密码"
|
||
style={{ flexGrow: 1 }}
|
||
value={changeUserPawFrom.Pwd}
|
||
onChange={(e) => {
|
||
setChangeUserPawFrom({
|
||
...changeUserPawFrom,
|
||
Pwd: e.target.value,
|
||
});
|
||
}}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<span>确认密码:</span>
|
||
<Input.Password
|
||
placeholder="再次输入密码"
|
||
style={{ flexGrow: 1 }}
|
||
value={changeUserPawFrom.newPwd}
|
||
onChange={(e) => {
|
||
setChangeUserPawFrom({
|
||
...changeUserPawFrom,
|
||
newPwd: e.target.value,
|
||
});
|
||
}}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div style={{
|
||
display: 'flex', justifyContent: 'center'
|
||
}}>
|
||
<Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }} onClick={() => setChangeUserPawModal(false)}>取消</Button>
|
||
<Button type="primary" className='m-ant-btn' onClick={async () => {
|
||
if (!changeUserPawFrom.Pwd || !changeUserPawFrom.newPwd) {
|
||
return message.error('请输入密码!')
|
||
}
|
||
if (changeUserPawFrom.Pwd !== changeUserPawFrom.newPwd) {
|
||
return message.error('新密码与确认密码不一致!')
|
||
}
|
||
|
||
await PutUserPwd({ id: addUserFrom.Id, pwd: CryptoJS.MD5(changeUserPawFrom.Pwd).toString(CryptoJS.enc.Hex) }).then(res => {
|
||
if (res.code === 200) {
|
||
setChangeUserPawModal(false)
|
||
message.success('修改成功')
|
||
}
|
||
})
|
||
await getUserList()
|
||
}}>修改</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
<Modal title='' open={deleteUserPawModal} footer={null} centered width={'300px'} closable={false}>
|
||
<div>
|
||
<div style={{ color: 'white', fontSize: '18px', textAlign: 'center', marginBottom: '20px' }}>
|
||
是否确认删除该用户?
|
||
</div>
|
||
<div style={{
|
||
display: 'flex', justifyContent: 'center'
|
||
}}>
|
||
<Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }}
|
||
onClick={() => setDeleteUserPawModal(false)}>取消</Button>
|
||
<Button type="primary" className='m-ant-btn' onClick={() => {
|
||
DeleteUser(selectedRowKeys).then(res => {
|
||
if (res.code === 200) {
|
||
setDeleteUserPawModal(false)
|
||
message.success('删除成功!')
|
||
getUserList()
|
||
}
|
||
})
|
||
}}>确定</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
<Modal title='批量导入用户' open={changeImportModal} onCancel={() => setChangeImportModal(false)} footer={null} centered width={'300px'}>
|
||
<div>
|
||
<div>
|
||
<Button type="primary" className='m-ant-btn' style={{ width: '100%', marginBottom: '10px' }}
|
||
onClick={async () => {
|
||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||
await fileUpLoad({
|
||
url: 'https://wgshare.oss-cn-chengdu.aliyuncs.com/%E7%94%A8%E6%88%B7%E6%89%B9%E9%87%8F%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF%E8%A1%A8.xlsx',
|
||
content: `下载导入模板成功!文件已保存至:${setting.shareFilesPath}`,
|
||
fileName: `用户批量导入模板表_${+new Date()}.xlsx`
|
||
})
|
||
}}
|
||
>
|
||
下载导入模版
|
||
</Button>
|
||
</div>
|
||
<div>
|
||
<Button type="primary" className='m-ant-btn' style={{ width: '100%' }}
|
||
onClick={() => {
|
||
const file = document.createElement("input") as any;
|
||
file.type = "file";
|
||
// file.accept = ".xls,.xlsx";
|
||
file.onchange = async () => {
|
||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||
const fileInfo = file.files[0];
|
||
const formData = new FormData();
|
||
formData.append("file", fileInfo);
|
||
await PostUserImport(formData).then(res => {
|
||
if (res.code === 200) {
|
||
if (res.data.item1) {
|
||
if (list.pageIndex === 1) {
|
||
getUserList()
|
||
} else {
|
||
setList({
|
||
...list,
|
||
pageIndex: 1
|
||
})
|
||
}
|
||
message.success(res.data.item3)
|
||
} else {
|
||
if (res.data.item2) {
|
||
const fileName = res.data.item2.split('/').pop().split('?')[0];
|
||
fileUpLoad({
|
||
url: res.data.item2,
|
||
content: `导入模板失败!失败文件已保存至:${setting.shareFilesPath}`,
|
||
fileName
|
||
})
|
||
}
|
||
message.error(res.data.item3)
|
||
}
|
||
}
|
||
})
|
||
setChangeImportModal(false)
|
||
};
|
||
file.click();
|
||
}}
|
||
>
|
||
选择导入文件
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
<StupWizard ref={stupWizardRef} />
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default User
|