diff --git a/config/router.config.ts b/config/router.config.ts index d66c0a2..05d1f16 100644 --- a/config/router.config.ts +++ b/config/router.config.ts @@ -140,6 +140,12 @@ export default [ path: '/biddingAnnouncement/BiddingAnnoStructureForm', component: './Bid/BiddingAnnouncement/structure/BiddingAnnoStructureForm', }, + //供应商账号管理 + { + name: '供应商', + path: '/SupplierUser', + component: './System/SupplierUser', + }, //==============================================================引入的业务路由 ...approvalForm,//审批单 ...juryRoom,//评标室内所有路由 diff --git a/src/pages/System/SupplierUser/components/UpdateForm.tsx b/src/pages/System/SupplierUser/components/UpdateForm.tsx new file mode 100644 index 0000000..ef7ab09 --- /dev/null +++ b/src/pages/System/SupplierUser/components/UpdateForm.tsx @@ -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; +} + +const FormItem = Form.Item; +const { Option } = Select; + +const UpdateForm: React.FC = (props) => { + const [form] = Form.useForm(); + const { updateModalVisible, onCancel, onSubmit, values } = props; + + const handleSubmit = async () => { + const fieldsValue = await form.validateFields(); + onSubmit({ ...values, ...fieldsValue }); + }; + + return ( + +
+ + + + + + + + + + + + + + + + + + +
+
+ ); +}; + +export default UpdateForm; \ No newline at end of file diff --git a/src/pages/System/SupplierUser/data.d.ts b/src/pages/System/SupplierUser/data.d.ts new file mode 100644 index 0000000..9f17c90 --- /dev/null +++ b/src/pages/System/SupplierUser/data.d.ts @@ -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; +} + +export interface TableListParams { + pageSize?: number; + current?: number; + keyword?: string; + status?: number; + sorter?: string; +} \ No newline at end of file diff --git a/src/pages/System/SupplierUser/index.tsx b/src/pages/System/SupplierUser/index.tsx new file mode 100644 index 0000000..638cae0 --- /dev/null +++ b/src/pages/System/SupplierUser/index.tsx @@ -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(); + const [updateModalVisible, handleUpdateModalVisible] = useState(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[] = [ + { + 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) => [ + { + handleUpdateModalVisible(true); + setFormValues(record); + }} + > + 修改 + , + handleResetPassword(record.username)} + key="reset" + > + 重置密码 + , + ], + }, + ]; + + return ( + + + 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} + /> + { + const success = await handleUpdate(value); + if (success) { + handleUpdateModalVisible(false); + setFormValues({}); + if (actionRef.current) { + actionRef.current.reload(); + } + } + }} + onCancel={() => { + handleUpdateModalVisible(false); + setFormValues({}); + }} + updateModalVisible={updateModalVisible} + values={formValues} + /> + + ); +}; + +export default SupplierUser; \ No newline at end of file diff --git a/src/pages/System/SupplierUser/service.ts b/src/pages/System/SupplierUser/service.ts new file mode 100644 index 0000000..198f4f7 --- /dev/null +++ b/src/pages/System/SupplierUser/service.ts @@ -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 }, + }); +} \ No newline at end of file diff --git a/src/pages/System/User/index.tsx b/src/pages/System/User/index.tsx index 5edbf69..dcab4d7 100644 --- a/src/pages/System/User/index.tsx +++ b/src/pages/System/User/index.tsx @@ -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([]); + 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 (
@@ -266,11 +316,36 @@ const entrust: React.FC<{}> = () => { }) } toolBarRender={() => [ - // , - ] - } + , + , + { + if (info.file.status === 'done') { + message.success('导入成功'); + //导入后刷新主表 + actionRef.current?.reload(); + } else if (info.file.status === 'error') { + message.error('导入失败'); + } + }} + > + + + ]} 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 */} + setSyncModalOpen(false)} + footer={null} + width={900} + > + { setIamSearch(v); setIamPage({ ...iamPage, pageNo: 1 }); }} + style={{ marginBottom: 16, width: 300 }} + allowClear + /> + ( + + ), + }, + ]} + 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" + /> +
- {/* 查看 */}
) }; diff --git a/src/pages/System/User/service.ts b/src/pages/System/User/service.ts index 1722a17..318c3d4 100644 --- a/src/pages/System/User/service.ts +++ b/src/pages/System/User/service.ts @@ -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 { -// 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, + }); +}