新增供应商账号管理功能,包括供应商用户列表、用户信息更新和密码重置功能。
This commit is contained in:
@ -140,6 +140,12 @@ export default [
|
||||
path: '/biddingAnnouncement/BiddingAnnoStructureForm',
|
||||
component: './Bid/BiddingAnnouncement/structure/BiddingAnnoStructureForm',
|
||||
},
|
||||
//供应商账号管理
|
||||
{
|
||||
name: '供应商',
|
||||
path: '/SupplierUser',
|
||||
component: './System/SupplierUser',
|
||||
},
|
||||
//==============================================================引入的业务路由
|
||||
...approvalForm,//审批单
|
||||
...juryRoom,//评标室内所有路由
|
||||
|
99
src/pages/System/SupplierUser/components/UpdateForm.tsx
Normal file
99
src/pages/System/SupplierUser/components/UpdateForm.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import { Modal, Form, Input, Select } from 'antd';
|
||||
import type { SupplierUserListItem } from '../data.d';
|
||||
|
||||
export interface UpdateFormProps {
|
||||
onCancel: () => void;
|
||||
onSubmit: (values: SupplierUserListItem) => void;
|
||||
updateModalVisible: boolean;
|
||||
values: Partial<SupplierUserListItem>;
|
||||
}
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { Option } = Select;
|
||||
|
||||
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
|
||||
const [form] = Form.useForm();
|
||||
const { updateModalVisible, onCancel, onSubmit, values } = props;
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const fieldsValue = await form.validateFields();
|
||||
onSubmit({ ...values, ...fieldsValue });
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
destroyOnClose
|
||||
title="修改供应商用户"
|
||||
visible={updateModalVisible}
|
||||
onCancel={onCancel}
|
||||
onOk={handleSubmit}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
initialValues={{
|
||||
username: values.username,
|
||||
name: values.name,
|
||||
mobile: values.mobile,
|
||||
status: values.status,
|
||||
email: values.email,
|
||||
remark: values.remark,
|
||||
}}
|
||||
layout="vertical"
|
||||
>
|
||||
<FormItem
|
||||
name="username"
|
||||
label="用户名"
|
||||
rules={[{ required: true, message: '请输入用户名' }]}
|
||||
>
|
||||
<Input disabled placeholder="请输入用户名" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="name"
|
||||
label="姓名"
|
||||
rules={[{ required: true, message: '请输入姓名' }]}
|
||||
>
|
||||
<Input placeholder="请输入姓名" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="mobile"
|
||||
label="手机号"
|
||||
rules={[
|
||||
{ required: true, message: '请输入手机号' },
|
||||
{ pattern: /^1\d{10}$/, message: '手机号格式不正确' },
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入手机号" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="email"
|
||||
label="邮箱"
|
||||
rules={[
|
||||
{ required: false },
|
||||
{ type: 'email', message: '邮箱格式不正确' },
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入邮箱" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="status"
|
||||
label="状态"
|
||||
rules={[{ required: true, message: '请选择状态' }]}
|
||||
>
|
||||
<Select placeholder="请选择状态">
|
||||
<Option value={1}>有效</Option>
|
||||
<Option value={0}>无效</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="remark"
|
||||
label="备注"
|
||||
>
|
||||
<Input.TextArea placeholder="请输入备注" rows={4} />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateForm;
|
30
src/pages/System/SupplierUser/data.d.ts
vendored
Normal file
30
src/pages/System/SupplierUser/data.d.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
export interface SupplierUserListItem {
|
||||
userId: string;
|
||||
username: string;
|
||||
name: string;
|
||||
mobile: string;
|
||||
supplierName: string;
|
||||
creditCode: string;
|
||||
status: number;
|
||||
email?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface TableListPagination {
|
||||
total: number;
|
||||
pageSize: number;
|
||||
current: number;
|
||||
}
|
||||
|
||||
export interface TableListData {
|
||||
list: SupplierUserListItem[];
|
||||
pagination: Partial<TableListPagination>;
|
||||
}
|
||||
|
||||
export interface TableListParams {
|
||||
pageSize?: number;
|
||||
current?: number;
|
||||
keyword?: string;
|
||||
status?: number;
|
||||
sorter?: string;
|
||||
}
|
178
src/pages/System/SupplierUser/index.tsx
Normal file
178
src/pages/System/SupplierUser/index.tsx
Normal file
@ -0,0 +1,178 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Button, message, Popconfirm } from 'antd';
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import type { ProColumns, ActionType } from '@ant-design/pro-table';
|
||||
import ProTable from '@ant-design/pro-table';
|
||||
import type { SupplierUserListItem } from './data.d';
|
||||
import { getSupplierUserList, updateSupplierUser, resetPassword } from './service';
|
||||
import UpdateForm from './components/UpdateForm';
|
||||
|
||||
const SupplierUser: React.FC = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
|
||||
const [formValues, setFormValues] = useState({});
|
||||
|
||||
// 从URL查询参数获取并保存必要的参数
|
||||
useEffect(() => {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
const token = query.get('token');
|
||||
const roleCode = query.get('roleCode');
|
||||
const mall3Check = query.get('mall3Check');
|
||||
|
||||
// 如果参数存在,保存到sessionStorage中
|
||||
if (token) {
|
||||
sessionStorage.setItem('Authorization', token);
|
||||
}
|
||||
|
||||
if (roleCode) {
|
||||
// 保存roleCode到sessionStorage
|
||||
try {
|
||||
const currentRoleData = sessionStorage.getItem('roleData');
|
||||
if (currentRoleData) {
|
||||
const roleDataObj = JSON.parse(currentRoleData);
|
||||
roleDataObj.roleCode = roleCode;
|
||||
sessionStorage.setItem('roleData', JSON.stringify(roleDataObj));
|
||||
} else {
|
||||
// 如果没有roleData,创建一个基本对象
|
||||
sessionStorage.setItem('roleData', JSON.stringify({ roleCode }));
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果解析失败,直接创建新对象
|
||||
sessionStorage.setItem('roleData', JSON.stringify({ roleCode }));
|
||||
}
|
||||
}
|
||||
|
||||
if (mall3Check) {
|
||||
sessionStorage.setItem('Mall3Check', mall3Check);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleUpdate = async (fields: SupplierUserListItem) => {
|
||||
const hide = message.loading('正在更新');
|
||||
try {
|
||||
await updateSupplierUser(fields);
|
||||
hide();
|
||||
message.success('更新成功');
|
||||
return true;
|
||||
} catch (error) {
|
||||
hide();
|
||||
message.error('更新失败请重试!');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetPassword = async (username: string) => {
|
||||
const hide = message.loading('正在重置密码');
|
||||
try {
|
||||
await resetPassword(username);
|
||||
hide();
|
||||
message.success('密码重置成功,新密码已通过邮件发送,请注意查收');
|
||||
return true;
|
||||
} catch (error) {
|
||||
hide();
|
||||
message.error('密码重置失败,请重试');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ProColumns<SupplierUserListItem>[] = [
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'username',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '供应商名称',
|
||||
dataIndex: 'supplierName',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '统一信用代码',
|
||||
dataIndex: 'creditCode',
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
dataIndex: 'mobile',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
valueEnum: {
|
||||
0: { text: '无效', status: 'Default' },
|
||||
1: { text: '有效', status: 'Processing' },
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'option',
|
||||
valueType: 'option',
|
||||
render: (_, record) => [
|
||||
<a
|
||||
key="config"
|
||||
onClick={() => {
|
||||
handleUpdateModalVisible(true);
|
||||
setFormValues(record);
|
||||
}}
|
||||
>
|
||||
修改
|
||||
</a>,
|
||||
<Popconfirm
|
||||
title="确认重置该用户的密码?"
|
||||
onConfirm={() => handleResetPassword(record.username)}
|
||||
key="reset"
|
||||
>
|
||||
<a>重置密码</a>
|
||||
</Popconfirm>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<ProTable<SupplierUserListItem>
|
||||
headerTitle="供应商用户列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="userId"
|
||||
search={{
|
||||
labelWidth: 120,
|
||||
}}
|
||||
request={(params) =>
|
||||
getSupplierUserList(params).then((res) => {
|
||||
return {
|
||||
data: res.data.records,
|
||||
success: true,
|
||||
total: res.data.total,
|
||||
};
|
||||
})
|
||||
}
|
||||
columns={columns}
|
||||
/>
|
||||
<UpdateForm
|
||||
onSubmit={async (value) => {
|
||||
const success = await handleUpdate(value);
|
||||
if (success) {
|
||||
handleUpdateModalVisible(false);
|
||||
setFormValues({});
|
||||
if (actionRef.current) {
|
||||
actionRef.current.reload();
|
||||
}
|
||||
}
|
||||
}}
|
||||
onCancel={() => {
|
||||
handleUpdateModalVisible(false);
|
||||
setFormValues({});
|
||||
}}
|
||||
updateModalVisible={updateModalVisible}
|
||||
values={formValues}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default SupplierUser;
|
23
src/pages/System/SupplierUser/service.ts
Normal file
23
src/pages/System/SupplierUser/service.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import request from '@/utils/request';
|
||||
import type { SupplierUserListItem, TableListParams } from './data.d';
|
||||
|
||||
export async function getSupplierUserList(params: TableListParams) {
|
||||
return request('/sys/supplier/user/list', {
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateSupplierUser(params: SupplierUserListItem) {
|
||||
return request('/sys/supplier/user/update', {
|
||||
method: 'POST',
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
export async function resetPassword(username: string) {
|
||||
return request('/sys/supplier/user/reset-password', {
|
||||
method: 'POST',
|
||||
data: { username },
|
||||
});
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
import React, { useState, useRef, useMemo, useEffect } from 'react';
|
||||
import { message, Modal, Input, Form, PageHeader, Button, Spin, Tree, Checkbox, Row, Col } from 'antd';
|
||||
import { message, Modal, Input, Form, PageHeader, Button, Spin, Tree, Checkbox, Row, Col, Upload } from 'antd';
|
||||
import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table';
|
||||
import tableProps from '@/utils/tableProps';
|
||||
import { getPage, getDataById, allocationIF, assignsRoles, updateRole } from './service';
|
||||
import { fetchAllDepartment } from '../Department/service';
|
||||
import { getDicData } from '@/utils/session';
|
||||
import { fetchIamUsers, syncIamUser } from './service';
|
||||
import { UploadOutlined, DownloadOutlined } from '@ant-design/icons';
|
||||
const { Search } = Input;
|
||||
const entrust: React.FC<{}> = () => {
|
||||
const [roleModalForm] = Form.useForm();
|
||||
@ -21,6 +23,12 @@ const entrust: React.FC<{}> = () => {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 13 },
|
||||
};
|
||||
const [syncModalOpen, setSyncModalOpen] = useState(false);
|
||||
const [iamUsers, setIamUsers] = useState<any[]>([]);
|
||||
const [iamLoading, setIamLoading] = useState(false);
|
||||
const [iamTotal, setIamTotal] = useState(0);
|
||||
const [iamPage, setIamPage] = useState({ pageNo: 1, pageSize: 10 });
|
||||
const [iamSearch, setIamSearch] = useState('');
|
||||
useEffect(() => {
|
||||
getDepartmentList();
|
||||
}, []);
|
||||
@ -168,7 +176,7 @@ const entrust: React.FC<{}> = () => {
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
const node = tree[i];
|
||||
if (node.children) {
|
||||
if (node.children.some((item) => item.key === key)) {
|
||||
if (node.children.some((item: { key: any }) => item.key === key)) {
|
||||
parentKey = node.key;
|
||||
} else if (getParentKey(key, node.children)) {
|
||||
parentKey = getParentKey(key, node.children);
|
||||
@ -191,7 +199,7 @@ const entrust: React.FC<{}> = () => {
|
||||
const loop = (data: any): any[] => {
|
||||
console.log('data', data);
|
||||
let res: any[] = [];
|
||||
data.map((item: any, i: any) => {
|
||||
data.map((item: { title: string; key: any; children?: any[] }, i: number) => {
|
||||
const strTitle = item.title as string;
|
||||
const index = strTitle.indexOf(searchValue);
|
||||
const beforeStr = strTitle.substring(0, index);
|
||||
@ -223,6 +231,48 @@ const entrust: React.FC<{}> = () => {
|
||||
return allData;
|
||||
}
|
||||
}, [searchValue, allData]);
|
||||
// IAM用户加载
|
||||
const loadIamUsers = async (pageNo: number, pageSize: number, search: string) => {
|
||||
setIamLoading(true);
|
||||
try {
|
||||
const res = await fetchIamUsers({
|
||||
pageNo,
|
||||
pageSize,
|
||||
search,
|
||||
});
|
||||
setIamUsers(res.data || []);
|
||||
setIamTotal(res.total || 0);
|
||||
} finally {
|
||||
setIamLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (syncModalOpen) {
|
||||
loadIamUsers(iamPage.pageNo, iamPage.pageSize, iamSearch);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [syncModalOpen, iamPage.pageNo, iamPage.pageSize, iamSearch]);
|
||||
|
||||
const handleSyncUser = async (user: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认同步该用户信息到主表?',
|
||||
content: `姓名:${user.name},工号:${user.employeeNo}`,
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await syncIamUser(user);
|
||||
message.success('同步成功');
|
||||
loadIamUsers(iamPage.pageNo, iamPage.pageSize, iamSearch);
|
||||
// 同步后刷新主表
|
||||
actionRef.current?.reload();
|
||||
} catch (e) {
|
||||
message.error('同步失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Spin spinning={spin}>
|
||||
<div style={{ maxHeight: innerHeight - 130, height: innerHeight - 130 }} className='xsy-entrust bgCWhite'>
|
||||
@ -266,11 +316,36 @@ const entrust: React.FC<{}> = () => {
|
||||
})
|
||||
}
|
||||
toolBarRender={() => [
|
||||
// <Button onClick={() => { handleAdd() }} type="primary">
|
||||
// 新增
|
||||
// </Button>,
|
||||
]
|
||||
}
|
||||
<Button onClick={() => setSyncModalOpen(true)} type="primary">同步用户信息</Button>,
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<DownloadOutlined />}
|
||||
style={{ marginRight: 8 }}
|
||||
onClick={() => {
|
||||
window.open('/user_import_template.xlsx');
|
||||
}}
|
||||
>
|
||||
下载导入模板
|
||||
</Button>,
|
||||
<Upload
|
||||
name="file"
|
||||
showUploadList={false}
|
||||
accept=".xls,.xlsx"
|
||||
action="/api/sys-manager-ebtp-project/v1/sysuser/import"
|
||||
headers={{ /* 如有token可加Authorization */ }}
|
||||
onChange={info => {
|
||||
if (info.file.status === 'done') {
|
||||
message.success('导入成功');
|
||||
//导入后刷新主表
|
||||
actionRef.current?.reload();
|
||||
} else if (info.file.status === 'error') {
|
||||
message.error('导入失败');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button icon={<UploadOutlined />}>导入Excel</Button>
|
||||
</Upload>
|
||||
]}
|
||||
pagination={{
|
||||
...tableProps.pagination,
|
||||
onChange: (page, pageSize) => pageDataSet({ pageNo: page, pageSize: pageSize }),
|
||||
@ -279,10 +354,56 @@ const entrust: React.FC<{}> = () => {
|
||||
onReset={() => { pageDataSet({ pageNo: 1, pageSize: 10 }); setOrgId(''); }}
|
||||
/>
|
||||
{setRoleModal}
|
||||
{/* IAM用户同步Modal */}
|
||||
<Modal
|
||||
title="同步用户信息"
|
||||
visible={syncModalOpen}
|
||||
onCancel={() => setSyncModalOpen(false)}
|
||||
footer={null}
|
||||
width={900}
|
||||
>
|
||||
<Input.Search
|
||||
placeholder="请输入姓名/工号"
|
||||
onSearch={v => { setIamSearch(v); setIamPage({ ...iamPage, pageNo: 1 }); }}
|
||||
style={{ marginBottom: 16, width: 300 }}
|
||||
allowClear
|
||||
/>
|
||||
<ProTable
|
||||
rowKey="employeeNo"
|
||||
columns={[
|
||||
{ title: '工号', dataIndex: 'employeeNo' },
|
||||
{ title: '姓名', dataIndex: 'name' },
|
||||
{ title: '状态', dataIndex: 'employeeStatusDesc' },
|
||||
{ title: '公司', dataIndex: 'companyName' },
|
||||
{ title: '岗位', dataIndex: 'positionName' },
|
||||
{ title: '部门', dataIndex: 'departmentCode' },
|
||||
{ title: '手机号', dataIndex: 'mobile' },
|
||||
{ title: '邮箱', dataIndex: 'email' },
|
||||
{
|
||||
title: '操作',
|
||||
render: (_: any, record: any) => (
|
||||
<Button type="link" onClick={() => handleSyncUser(record)}>
|
||||
同步
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
]}
|
||||
dataSource={iamUsers}
|
||||
loading={iamLoading}
|
||||
pagination={{
|
||||
current: iamPage.pageNo,
|
||||
pageSize: iamPage.pageSize,
|
||||
total: iamTotal,
|
||||
onChange: (page, pageSize) => setIamPage({ pageNo: page, pageSize }),
|
||||
}}
|
||||
search={false}
|
||||
options={false}
|
||||
size="small"
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 查看 */}
|
||||
</Spin >
|
||||
)
|
||||
};
|
||||
|
@ -43,47 +43,18 @@ export async function assignsRoles(params: any) {
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
// import { TreeDataNode } from 'antd';
|
||||
// IAM用户列表查询
|
||||
export async function fetchIamUsers(params: any) {
|
||||
return request('/api/sys-manager-ebtp-project/v1/sysuser/iam/users', {
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
// export function userList(options?: { [key: string]: any }): Promise<{ data: any }> {
|
||||
// return request('/api/system/userList', {
|
||||
// method: 'GET',
|
||||
// ...(options || {}),
|
||||
// });
|
||||
// }
|
||||
|
||||
// export function treeData(options?: { [key: string]: any }): Promise<{ data: TreeDataNode[] }> {
|
||||
// return request('/api/system/treeData', {
|
||||
// method: 'GET',
|
||||
// ...(options || {}),
|
||||
// });
|
||||
// }
|
||||
|
||||
// export function fetchUserList(options?: any) {
|
||||
// return request('/api/sysuser/getPage', {
|
||||
// method: 'POST',
|
||||
// data: options,
|
||||
// });
|
||||
// }
|
||||
// //获取用户数据
|
||||
// export function getUser(userId?: any) {
|
||||
// return request(`/api/sysuser/${userId}`, {
|
||||
// method: 'get',
|
||||
// });
|
||||
// }
|
||||
|
||||
// export function assignsRoles(options?: { [key: string]: any }): Promise<any> {
|
||||
// return request('/api/sysuser/assignsRoles', {
|
||||
// method: 'post',
|
||||
// ...(options || {}),
|
||||
// });
|
||||
// }
|
||||
|
||||
// //查询用户详情
|
||||
// export function getOneUserAll(options?: { [key: string]: any }): Promise<{ data: TreeDataNode[] }> {
|
||||
// return request(`/api/sysuser/getOneUserAll/${options?.id}`, {
|
||||
// method: 'GET',
|
||||
// params: options,
|
||||
// ...(options || {}),
|
||||
// });
|
||||
// }
|
||||
// 同步IAM用户到主表
|
||||
export async function syncIamUser(user: any) {
|
||||
return request('/api/sys-manager-ebtp-project/v1/sysuser/sync', {
|
||||
method: 'post',
|
||||
data: user,
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user