WGShare.Client.Electron/src/page/Home/User/index.tsx

519 lines
18 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 styles from '@/page/Home/User/index.module.scss'
import { useEffect, useState } 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 } from '@/api/Home/User';
import * as CryptoJS from 'crypto-js';
import ImageUrl from '@/utils/package/imageUrl';
import { storage } from '@/utils';
const { Column } = Table
const { confirm } = Modal;
const { exec } = require('child_process');
const fs = require('fs').promises;
const User: React.FC = () => {
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [isCreateUser, setIsCreateUser] = useState(false);
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: ""
})
const [changeUserPawModal, setChangeUserPawModal] = useState(false)
const [changeImportModal, setChangeImportModal] = useState(false)
const [changeUserPawFrom, setChangeUserPawFrom] = useState({
Pwd: "",
newPwd: '',
})
const [deleteUserPawModal, setDeleteUserPawModal] = useState(false)
useEffect(() => {
getUserList()
}, [list.pageIndex]);
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,
}
}),
})
}
})
}
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('文件夹不存在!')
return
} else {
message.error(error)
}
}
}
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(true)
setAddUserFrom({
Id: "",
Account: "",
RoleId: null,
Pwd: "",
UserName: "",
})
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"
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="操作" render={(item) => (
<>
<Button
type="primary"
style={{ backgroundColor: '#0085FF30', marginRight: '14px' }}
size={'small'}
onClick={() => {
getRoleDpList((bool: boolean) => {
if (bool) {
setIsCreateUser(false)
setAddUserFrom({
...addUserFrom,
Id: item.id,
Account: item.account,
RoleId: item.roleId,
UserName: item.userName,
})
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={(e) => {
setList({
...list,
pageIndex: e
})
}} pageSize={list.pageSize} current={list.pageIndex} hideOnSinglePage={true} />
</div>
</div>
</div>
<Modal title={isCreateUser ? '添加用户' : '编辑用户'} open={addUserModal} footer={null} closable={false} centered width={'500px'}>
<div>
<div className={styles.addUserModal}>
<div>
<span></span>
<Input
style={{ flexGrow: 1 }}
placeholder="请输入账号"
maxLength={11}
showCount={true}
value={addUserFrom.Account}
onChange={(e) => {
const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) {
setAddUserFrom({
...addUserFrom,
Account: e.target.value,
});
}
}}
/>
</div>
<div>
<span></span>
<Select
placeholder='请选择角色'
options={roleList}
style={{ flexGrow: 1 }}
value={addUserFrom.RoleId} onChange={(e) => {
setAddUserFrom({
...addUserFrom,
RoleId: e
});
}} />;
</div>
{isCreateUser ? <div>
<span></span>
<Input.Password
placeholder="请输入密码"
style={{ flexGrow: 1 }}
value={addUserFrom.Pwd}
onChange={(e) => {
setAddUserFrom({
...addUserFrom,
Pwd: e.target.value,
});
}}
/>
</div> : null}
<div>
<span></span>
<Input
placeholder="请输入用户名称"
style={{ flexGrow: 1 }}
value={addUserFrom.UserName}
onChange={(e) => {
setAddUserFrom({
...addUserFrom,
UserName: e.target.value,
});
}}
/>
</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) {
return message.error('请输入账号!')
}
if (!addUserFrom.RoleId) {
return message.error('请选择角色!')
}
if (!addUserFrom.Pwd && isCreateUser) {
return message.error('请输入密码!')
}
if (!addUserFrom.UserName) {
return message.error('请输入用户名称!')
}
if (isCreateUser) {
await PostUser({
...addUserFrom,
Pwd: CryptoJS.MD5(addUserFrom.Pwd).toString(CryptoJS.enc.Hex)
}).then(res => {
if (res.code === 200) {
setAddUserModal(false)
message.success('添加成功!')
}
})
} else {
await PutUser({
Id: addUserFrom.Id,
Account: addUserFrom.Account,
RoleId: addUserFrom.RoleId,
UserName: addUserFrom.UserName
}).then(res => {
if (res.code === 200) {
setAddUserModal(false)
message.success('修改成功!')
}
})
}
await getUserList()
}}>{isCreateUser ? '添加' : '修改'}</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)
setSelectedRowKeys([])
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) {
message.success('导入成功')
if (list.pageIndex === 1) {
getUserList()
} else {
setList({
...list,
pageIndex: 1
})
}
} else {
if (res.data.item2) {
const fileName = res.data.item2.split('/').pop().split('?')[0];
fileUpLoad({
url: res.data.item2,
content: `导入模板失败!失败文件已保存至:${setting.shareFilesPath}`,
fileName
})
} else {
message.error('导入失败')
}
}
}
})
setChangeImportModal(false)
};
file.click();
}}
>
</Button>
</div>
</div>
</Modal>
</>
)
}
export default User