From 9a45e65db101e435f1b24439de9074a897692668 Mon Sep 17 00:00:00 2001 From: linxd <544554903@qq.com> Date: Tue, 24 Jun 2025 14:49:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85=E9=80=89=E6=8B=A9=E4=BE=9B?= =?UTF-8?q?=E5=BA=94=E5=95=86=E7=BB=84=E4=BB=B6;=20=E4=B8=B0=E5=AF=8C?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=93=81=E7=B1=BB=E5=BA=93=20=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CategorySelector/CategorySelector.less | 39 ++ .../CategorySelector/CategorySelector.tsx | 310 +++++++------- src/components/CategorySelector/README.md | 173 ++++++++ src/components/SupplierSelector/README.md | 271 ++++++++++++ .../SupplierSelector/SupplierSelector.less | 31 ++ .../SupplierSelector/SupplierSelector.tsx | 388 +++++++++++++++++ src/components/SupplierSelector/index.ts | 3 + .../supplierEvaluateResult.tsx | 4 +- .../supplierEvaluateResultInfo.tsx | 4 +- .../components/BasicInfoStep.tsx | 20 +- .../components/SupplierSelectStep.tsx | 396 +----------------- .../supplierTaskManageAdd.tsx | 2 +- src/servers/api/supplier.ts | 71 ++++ 13 files changed, 1153 insertions(+), 559 deletions(-) create mode 100644 src/components/CategorySelector/README.md create mode 100644 src/components/SupplierSelector/README.md create mode 100644 src/components/SupplierSelector/SupplierSelector.less create mode 100644 src/components/SupplierSelector/SupplierSelector.tsx create mode 100644 src/components/SupplierSelector/index.ts create mode 100644 src/servers/api/supplier.ts diff --git a/src/components/CategorySelector/CategorySelector.less b/src/components/CategorySelector/CategorySelector.less index c37f4a6..be42327 100644 --- a/src/components/CategorySelector/CategorySelector.less +++ b/src/components/CategorySelector/CategorySelector.less @@ -1,22 +1,61 @@ +/* + * CategorySelector组件样式 + * 用于控制品类选择器的整体布局和样式 + */ .category-selector { + /* 控制触发器样式 */ .selector-trigger { display: flex; align-items: center; cursor: pointer; + border-radius: 2px; + transition: all 0.3s; + /* 悬停效果 */ + &:hover { + background-color: rgba(0, 0, 0, 0.02); + } + + /* 已选择品类的展示区域 */ .selected-categories { margin-left: 8px; display: flex; flex-wrap: wrap; max-width: 80%; + /* 标签样式 */ .ant-tag { margin-bottom: 4px; + margin-right: 4px; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; } } } + /* 搜索框样式 */ .search-container { margin-bottom: 16px; + padding: 8px; + border-bottom: 1px solid #f0f0f0; + } + + /* 优化TreeSelect下拉菜单样式 */ + .ant-select-tree { + padding: 8px 4px; + + .ant-select-tree-node-content-wrapper { + transition: all 0.3s; + + &:hover { + background-color: #f5f5f5; + } + } + + /* 高亮选中节点 */ + .ant-select-tree-node-selected { + background-color: #e6f7ff; + } } } diff --git a/src/components/CategorySelector/CategorySelector.tsx b/src/components/CategorySelector/CategorySelector.tsx index 3c7764b..50f2ffd 100644 --- a/src/components/CategorySelector/CategorySelector.tsx +++ b/src/components/CategorySelector/CategorySelector.tsx @@ -1,191 +1,177 @@ import React, { useState, useEffect } from 'react'; -import { Button, Modal, Table, Input, Tag, Space } from 'antd'; -import { SearchOutlined } from '@ant-design/icons'; -import type { TableRowSelection } from 'antd/es/table/interface'; +import { TreeSelect, message, Spin } from 'antd'; +import { getCategoryTree } from '@/servers/api/supplierEvaluate'; import './CategorySelector.less'; +/** + * CategorySelector组件的属性接口 + * @interface CategorySelectorProps + * @property {string | string[]} [value] - 当前选中的品类ID或ID数组 + * @property {Function} [onChange] - 选择变化时的回调函数 + * @property {boolean} [disabled] - 是否禁用选择器 + * @property {boolean} [multiple] - 是否支持多选,默认为true + * @property {string} [placeholder] - 占位文本 + * @property {React.CSSProperties} [style] - 自定义样式 + */ interface CategorySelectorProps { value?: string | string[]; onChange?: (value: string | string[]) => void; disabled?: boolean; multiple?: boolean; // 是否多选,默认为多选 + placeholder?: string; // 占位文本 + style?: React.CSSProperties; // 自定义样式 } -interface CategoryItem { - id: string; - name: string; - code: string; +/** + * TreeSelect节点类型接口 + * @interface TreeSelectNode + * @property {React.ReactNode} title - 节点显示的标题 + * @property {string} key - 节点唯一标识 + * @property {string} value - 节点选中时的值 + * @property {TreeSelectNode[]} [children] - 子节点 + * @property {boolean} [isLeaf] - 是否为叶子节点 + * @property {boolean} [selectable] - 是否可选 + * @property {boolean} [disabled] - 是否禁用 + */ +interface TreeSelectNode { + title: React.ReactNode; + key: string; + value: string; + children?: TreeSelectNode[]; + isLeaf?: boolean; + selectable?: boolean; + disabled?: boolean; } +const { SHOW_CHILD } = TreeSelect; + +/** + * 品类选择器组件 + * 用于从树形结构中选择品类,支持单选和多选模式 + * + * @param {CategorySelectorProps} props - 组件属性 + * @returns {React.ReactElement} 品类选择器组件 + */ const CategorySelector: React.FC = ({ - value = [], + value, onChange, disabled = false, - multiple = true + multiple = true, + placeholder = '请选择品类', + style = { width: '100%' } }) => { - const [visible, setVisible] = useState(false); - const [selectedCategories, setSelectedCategories] = useState([]); - const [categoryData, setCategoryData] = useState([]); - const [selectedRowKeys, setSelectedRowKeys] = useState([]); - const [searchValue, setSearchValue] = useState(''); + // 树形数据状态 + const [treeData, setTreeData] = useState([]); + // 加载状态 + const [loading, setLoading] = useState(false); - // 初始化数据 + /** + * 将后端返回的品类数据格式化为TreeSelect需要的格式 + * @param {any[]} data - 后端返回的原始品类数据 + * @returns {TreeSelectNode[]} 格式化后的树形数据 + */ + const formatCategoryTreeData = (data: any[]): TreeSelectNode[] => { + if (!data || !Array.isArray(data) || data.length === 0) return []; + + return data.map(item => { + if (!item || typeof item !== 'object') return null; + + // 类型为1的节点是叶子节点,只有叶子节点可选 + const isLeaf = item.type === '1'; + const node: TreeSelectNode = { + title: item.categoryName || '未命名', + key: item.id || `key-${Math.random()}`, + value: item.id || `value-${Math.random()}`, + isLeaf: isLeaf, + selectable: isLeaf, + disabled: !isLeaf, // 非叶子节点不可选 + }; + + // 递归处理子节点 + if (Array.isArray(item.children) && item.children.length > 0) { + const children = formatCategoryTreeData(item.children); + if (children.length > 0) { + node.children = children; + } + } + + return node; + }).filter(Boolean) as TreeSelectNode[]; // 过滤掉可能的null值 + }; + + /** + * 从API获取品类树数据 + */ + const fetchCategoryTree = () => { + setLoading(true); + + getCategoryTree().then(response => { + if (response && response.success && Array.isArray(response.data)) { + const formattedTreeData = formatCategoryTreeData(response.data); + setTreeData(formattedTreeData); + } else { + console.error('获取品类数据格式错误:', response); + message.error('获取品类数据失败'); + } + }).catch(error => { + console.error('获取品类数据失败:', error); + message.error('获取品类数据失败'); + }).finally(() => { + setLoading(false); + }); + }; + + /** + * 组件挂载时获取品类数据 + * 只在组件挂载时执行一次 + */ useEffect(() => { - // 将输入值转换为数组 - const valueArray = Array.isArray(value) ? value : value ? [value] : []; - - // 只有当value真正变化时才更新状态 - if (JSON.stringify(valueArray) !== JSON.stringify(selectedCategories)) { - setSelectedCategories(valueArray); - // 将选中的品类ID转换为rowKey数组 - const selectedKeys = valueArray.map(categoryId => { - return categoryId; - }).filter(Boolean); - setSelectedRowKeys(selectedKeys); - } - }, [value]); - - // 模拟获取品类数据 - useEffect(() => { - // 模拟API请求 - const mockData: CategoryItem[] = [ - { id: '1', name: '电子', code: 'DZ001' }, - { id: '2', name: '机械', code: 'JX001' }, - { id: '3', name: '化工', code: 'HG001' }, - { id: '4', name: '医药', code: 'YY001' }, - { id: '5', name: '食品', code: 'SP001' }, - { id: '6', name: '服装', code: 'FZ001' }, - { id: '7', name: '建材', code: 'JC001' }, - { id: '8', name: '家电', code: 'JD001' }, - { id: '9', name: '汽车', code: 'QC001' }, - { id: '10', name: '能源', code: 'NY001' }, - ]; - setCategoryData(mockData); - - // 初始化选中的行 - const valueArray = Array.isArray(value) ? value : value ? [value] : []; - if (valueArray.length > 0) { - setSelectedRowKeys(valueArray); - } + fetchCategoryTree(); }, []); - // 打开选择弹窗 - const showModal = () => { - if (disabled) return; - setVisible(true); - }; - - // 处理确认选择 - const handleOk = () => { - // 根据selectedRowKeys获取对应的品类数据 - const selectedIds = selectedRowKeys as string[]; - - // 只有当选择真正变化时才触发onChange - if (JSON.stringify(selectedIds) !== JSON.stringify(selectedCategories)) { - setSelectedCategories(selectedIds); - if (onChange) { - // 如果是单选模式,返回第一个选中的值,否则返回数组 - onChange(multiple ? selectedIds : selectedIds[0] || ''); - } + /** + * 处理选择变化 + * 将选择结果通过onChange回调传递给父组件 + * + * @param {string | string[]} newValue - 新的选择值 + */ + const handleChange = (newValue: string | string[]) => { + if (onChange) { + onChange(newValue); } - - setVisible(false); - }; - - // 处理取消选择 - const handleCancel = () => { - // 恢复到打开弹窗前的选择状态 - const valueArray = Array.isArray(value) ? value : value ? [value] : []; - setSelectedRowKeys(valueArray); - setVisible(false); - }; - - // 处理搜索 - const handleSearch = (e: React.ChangeEvent) => { - setSearchValue(e.target.value); - }; - - // 过滤数据 - const filteredData = categoryData.filter(item => - item.name.toLowerCase().includes(searchValue.toLowerCase()) || - item.code.toLowerCase().includes(searchValue.toLowerCase()) - ); - - // 获取已选择的品类名称 - const getSelectedCategoryNames = () => { - if (!selectedCategories || !Array.isArray(selectedCategories)) { - return []; - } - - return selectedCategories.map(categoryId => { - const category = categoryData.find(item => item.id === categoryId); - return category ? category.name : ''; - }).filter(Boolean); - }; - - const columns = [ - { - title: '品类编码', - dataIndex: 'code', - key: 'code', - }, - { - title: '品类名称', - dataIndex: 'name', - key: 'name', - }, - ]; - - // 表格行选择配置 - const rowSelection = { - selectedRowKeys, - onChange: (newSelectedRowKeys: React.Key[]) => { - // 如果是单选模式,只保留最后选择的一项 - if (!multiple && newSelectedRowKeys.length > 0) { - setSelectedRowKeys([newSelectedRowKeys[newSelectedRowKeys.length - 1]]); - } else { - setSelectedRowKeys(newSelectedRowKeys); - } - }, - type: multiple ? 'checkbox' as const : 'radio' as const, }; return (
-
- -
- {getSelectedCategoryNames().map((name, index) => ( - {name} - ))} -
-
- -
- } - value={searchValue} - onChange={handleSearch} - style={{ marginBottom: 16 }} - /> -
- + ) : ( + // 显示树形选择器 + { + // 自定义节点过滤逻辑,支持按标题搜索 + if (node && node.title) { + return String(node.title).toLowerCase().includes(inputValue.toLowerCase()); + } + return false; + }} /> - + )} ); }; diff --git a/src/components/CategorySelector/README.md b/src/components/CategorySelector/README.md new file mode 100644 index 0000000..da1f1b2 --- /dev/null +++ b/src/components/CategorySelector/README.md @@ -0,0 +1,173 @@ +# CategorySelector 品类选择器组件 + +品类选择器组件,用于从树形结构中选择产品或服务品类。支持单选和多选模式,具有搜索过滤功能。 + +## 组件特点 + +- 树形结构展示品类层级关系 +- 支持单选和多选模式 +- 支持搜索过滤功能 +- 仅叶子节点可选,中间节点不可选 +- 自动加载品类数据 +- 支持表单受控模式 + +## 使用场景 + +- 供应商评估任务中选择相关品类 +- 供应商准入管理中设置品类范围 +- 任何需要选择产品品类或服务类别的场景 + +## 使用方法 + +### 基础用法 + +```jsx +import React, { useState } from 'react'; +import { CategorySelector } from '@/components'; + +const Demo = () => { + const [selectedCategories, setSelectedCategories] = useState([]); + + const handleCategoryChange = (categories) => { + setSelectedCategories(categories); + console.log('已选择的品类:', categories); + }; + + return ( + + ); +}; +``` + +### 单选模式 + +```jsx +import React, { useState } from 'react'; +import { CategorySelector } from '@/components'; + +const SingleSelectDemo = () => { + const [selectedCategory, setSelectedCategory] = useState(''); + + return ( + + ); +}; +``` + +### 配合表单使用 + +```jsx +import React from 'react'; +import { Form, Button } from 'antd'; +import { CategorySelector } from '@/components'; + +const FormDemo = () => { + const [form] = Form.useForm(); + + const handleFinish = (values) => { + console.log('表单提交的值:', values); + }; + + return ( +
+ + + + + + + + + ); +}; +``` + +### 自定义样式 + +```jsx +import React from 'react'; +import { CategorySelector } from '@/components'; + +const CustomStyleDemo = () => { + return ( + + ); +}; +``` + +## API + +### 组件属性 + +| 参数 | 说明 | 类型 | 默认值 | 是否必填 | +|------|------|------|--------|----------| +| value | 当前选中的品类ID或ID数组 | `string \| string[]` | - | 否 | +| onChange | 选择变化时的回调函数 | `(value: string \| string[]) => void` | - | 否 | +| disabled | 是否禁用选择器 | `boolean` | `false` | 否 | +| multiple | 是否支持多选 | `boolean` | `true` | 否 | +| placeholder | 占位文本 | `string` | `"请选择品类"` | 否 | +| style | 自定义样式 | `React.CSSProperties` | `{ width: '100%' }` | 否 | + +## 设计实现 + +组件基于 Ant Design 的 TreeSelect 组件开发,并与后端 API 集成,从服务器获取品类数据。主要特点: + +1. **纯受控组件**:完全符合 React 受控组件模式,方便与表单结合使用 +2. **树形数据处理**:后端返回的数据经过格式转换,适配 TreeSelect 的要求 +3. **性能优化**: + - 只在组件挂载时加载一次数据 + - 数据量大时不自动展开所有节点 + - 使用 `filter(Boolean)` 过滤空值,避免错误 +4. **用户体验优化**: + - 加载状态显示 + - 搜索过滤功能 + - 只允许选择叶子节点,防止选择中间类别 + +## 后端 API 集成 + +组件通过 `getCategoryTree` API 获取品类数据。预期的响应格式: + +```typescript +interface ApiResponse { + success: boolean; + data: CategoryItem[]; +} + +interface CategoryItem { + id: string; + categoryName: string; + type: string; // '1' 表示叶子节点 + children?: CategoryItem[]; +} +``` + +## 常见问题 + +### 1. 如何刷新品类数据? + +当前版本不支持手动刷新,品类数据只在组件挂载时加载一次。如需刷新功能,可以扩展组件添加刷新方法。 + +### 2. 如何自定义节点渲染? + +当前版本使用默认的节点渲染。如需自定义,可以通过修改组件源码添加 `treeNodeLabelProp` 或自定义 `title` 渲染函数。 + +### 3. 选择了品类但没有在表单中显示值? + +请确保正确传递了 `value` 和 `onChange` 属性,并在 Form.Item 中设置了正确的 `name` 属性。 diff --git a/src/components/SupplierSelector/README.md b/src/components/SupplierSelector/README.md new file mode 100644 index 0000000..8cff6f2 --- /dev/null +++ b/src/components/SupplierSelector/README.md @@ -0,0 +1,271 @@ +# SupplierSelector 供应商选择器组件 + +供应商选择器组件,用于从系统中选择供应商数据。提供双列表交互方式,支持搜索、分页和多选功能。 + +## 组件特点 + +- 支持搜索过滤供应商:可按名称、部门、公司名称和品类筛选 +- 支持分页加载更多供应商数据 +- 双列表展示(待选列表和已选列表),直观且易用 +- 支持初始化已选供应商 +- 支持多选和批量操作 +- 自动去重,避免重复选择同一供应商 +- 支持按部门列表筛选供应商 +- 可自定义显示的字段列 + +## 使用场景 + +- 供应商评估任务选择供应商 +- 供应商准入管理 +- 任何需要从多个供应商中选择一个或多个的场景 + +## 使用方法 + +### 基础用法 + +```jsx +import React, { useState } from 'react'; +import SupplierSelector from '@/components/SupplierSelector'; + +const Demo = () => { + const [selectedSuppliers, setSelectedSuppliers] = useState([]); + + const handleSupplierSelect = (suppliers) => { + setSelectedSuppliers(suppliers); + console.log('已选择的供应商:', suppliers); + }; + + return ( + + ); +}; +``` + +### 配合表单使用 + +```jsx +import React from 'react'; +import { Form, Button, Card } from 'antd'; +import SupplierSelector from '@/components/SupplierSelector'; + +const FormDemo = () => { + const [form] = Form.useForm(); + + const handleFinish = (values) => { + console.log('表单提交的值:', values); + }; + + return ( +
+ + + + + + + + + + + ); +}; +``` + +### 按部门筛选供应商 + +```jsx +import React, { useState } from 'react'; +import SupplierSelector from '@/components/SupplierSelector'; + +const DepartmentFilterDemo = () => { + const [selectedSuppliers, setSelectedSuppliers] = useState([]); + + // 部门ID列表,用于筛选供应商 + const deptList = ['1', '2', '3']; + + return ( + + ); +}; +``` + +### 带初始值的用法 + +```jsx +import React, { useState, useEffect } from 'react'; +import SupplierSelector from '@/components/SupplierSelector'; +import { getSuppliersByIds } from '@/servers/api/supplier'; + +const InitialValueDemo = () => { + const [selectedSuppliers, setSelectedSuppliers] = useState([]); + const [loading, setLoading] = useState(true); + + // 加载初始已选供应商 + useEffect(() => { + const loadInitialSuppliers = async () => { + setLoading(true); + try { + // 假设我们有一些预先选择的供应商ID + const initialIds = ['1', '2', '3']; + const response = await getSuppliersByIds(initialIds); + + if (response.code === 200) { + setSelectedSuppliers(response.data); + } + } catch (error) { + console.error('加载初始供应商失败:', error); + } finally { + setLoading(false); + } + }; + + loadInitialSuppliers(); + }, []); + + const handleSupplierSelect = (suppliers) => { + setSelectedSuppliers(suppliers); + }; + + return ( +
+ {loading ? ( +
加载中...
+ ) : ( + + )} +
+ ); +}; +``` + +## API + +### 组件属性 + +| 参数 | 说明 | 类型 | 默认值 | 是否必填 | +|------|------|------|--------|----------| +| selectedSuppliers | 已选择的供应商列表 | `Array` | `[]` | 否 | +| onSelect | 选择后的回调函数 | `(suppliers: SupplierItem[]) => void` | - | 否 | +| deptList | 部门ID列表,用于筛选供应商 | `string[]` | `[]` | 否 | +| showDeptFilter | 是否显示部门筛选条件 | `boolean` | `true` | 否 | +| showCompanyFilter | 是否显示公司名称筛选条件 | `boolean` | `false` | 否 | + +### 数据结构 + +#### SupplierItem + +供应商数据项结构,对应后端 SupplierPageVo + +```typescript +interface SupplierItem { + id: string; // 供应商ID + name: string; // 供应商名称 + deptId?: string; // 部门ID + deptName?: string; // 部门名称 + companyName?: string; // 公司名称 + categoryName?: string; // 所属品类 + levelName?: string; // 最新评价等级 + admissionTime?: Date; // 准入时间 + evaluationTime?: Date; // 最新评价时间 + [key: string]: any; // 其他属性 +} +``` + +## 后端接口对接 + +组件已对接 `/coscoSupplierBase/getSupplierPage` 接口,使用 POST 方法。请求参数格式: + +```javascript +{ + // 查询条件 + name: "供应商名称", // 可选,供应商名称 + deptId: "部门ID", // 可选,部门ID + deptName: "部门名称", // 可选,部门名称 + companyName: "公司名称", // 可选,公司名称 + categoryName: "所属品类", // 可选,所属品类 + + // 筛选条件 + deptList: ["部门ID1", "部门ID2"], // 可选,部门ID列表 + + // 分页信息 + basePageRequest: { + pageNo: 1, // 页码 + pageSize: 10 // 每页条数 + } +} +``` + +预期的响应格式: + +```javascript +{ + code: 200, // 状态码 + message: "success", // 消息 + data: { + records: [ // 供应商记录数组 + { + id: "1", // 供应商ID + name: "供应商A", // 供应商名称 + deptId: "1", // 部门ID + deptName: "采购部", // 部门名称 + companyName: "公司A", // 公司名称 + categoryName: "润滑油", // 所属品类 + levelName: "A", // 最新评价等级 + admissionTime: "2023-01-01", // 准入时间 + evaluationTime: "2023-06-01" // 最新评价时间 + } + // ...更多记录 + ], + total: 100 // 总记录数 + } +} +``` + +## 常见问题 + +### 1. 如何处理大量数据的情况? + +组件内部已实现分页加载,可以有效处理大量数据。API请求会自动附带分页参数。 + +### 2. 如何自定义显示的列? + +组件提供了 `showDeptFilter` 和 `showCompanyFilter` 属性来控制是否显示部门和公司名称列。如需更多自定义,可以通过修改组件源码中的 `columns` 配置实现。 + +### 3. 如何限制只从特定部门选择供应商? + +使用 `deptList` 属性可以限制只显示特定部门的供应商。例如: + +```jsx + +``` + +这样将只显示部门ID为1和2的供应商。 + +### 4. 如何处理接口错误情况? + +组件内置了错误处理机制,当接口请求失败时会显示错误提示,并使用模拟数据作为备用,确保界面不会崩溃。 + +## 设计考量 + +1. **双列表设计**:采用左右双列表设计,符合用户选择多项时的直觉操作 +2. **错误处理**:内置错误处理和备用数据,提高组件稳定性 +3. **性能优化**:使用Set进行去重操作,提高大数据量下的性能 +4. **灵活配置**:通过属性控制显示哪些列和筛选条件,适应不同场景需求 diff --git a/src/components/SupplierSelector/SupplierSelector.less b/src/components/SupplierSelector/SupplierSelector.less new file mode 100644 index 0000000..e914f5a --- /dev/null +++ b/src/components/SupplierSelector/SupplierSelector.less @@ -0,0 +1,31 @@ +.supplier-selector { + .supplier-lists { + margin-top: 12px; + } + + .list-title { + font-weight: 500; + margin-bottom: 8px; + padding-left: 8px; + border-left: 3px solid #1890ff; + } + + .transfer-buttons { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100%; + padding-top: 100px; + + .ant-btn { + margin: 8px 0; + } + } + + .search-count { + float: right; + color: rgba(0, 0, 0, 0.45); + font-size: 12px; + } +} diff --git a/src/components/SupplierSelector/SupplierSelector.tsx b/src/components/SupplierSelector/SupplierSelector.tsx new file mode 100644 index 0000000..246b0dd --- /dev/null +++ b/src/components/SupplierSelector/SupplierSelector.tsx @@ -0,0 +1,388 @@ +import React, { useState, useEffect } from 'react'; +import { Input, Select, Row, Col, Table, Button, Form, Tooltip, message } from 'antd'; +import { RightOutlined, LeftOutlined } from '@ant-design/icons'; +import { getSupplierPage } from '@/servers/api/supplier'; +import './SupplierSelector.less'; + +const { Option } = Select; + +/** + * SupplierSelector 组件的属性接口 + * @interface SupplierSelectorProps + * @property {Function} [onSelect] - 当选择供应商发生变化时的回调函数 + * @property {any[]} [selectedSuppliers] - 初始已选择的供应商列表 + * @property {string[]} [deptList] - 部门列表,用于筛选供应商 + * @property {boolean} [showDeptFilter] - 是否显示部门筛选,默认显示 + * @property {boolean} [showCompanyFilter] - 是否显示公司名称筛选,默认不显示 + */ +interface SupplierSelectorProps { + onSelect?: (selected: any[]) => void; + selectedSuppliers?: any[]; + deptList?: string[]; + showDeptFilter?: boolean; + showCompanyFilter?: boolean; +} + +/** + * 供应商数据项接口,对应后端SupplierPageVo + * @interface SupplierItem + * @property {string} id - 供应商ID + * @property {string} name - 供应商名称 + * @property {string} [deptId] - 部门ID + * @property {string} [deptName] - 部门名称 + * @property {string} [companyName] - 公司名称 + * @property {string} [categoryName] - 所属品类 + * @property {string} [levelName] - 最新评价等级 + * @property {Date} [admissionTime] - 准入时间 + * @property {Date} [evaluationTime] - 最新评价时间 + * @property {any} [key: string] - 其他属性 + */ +interface SupplierItem { + id: string; + name: string; + deptId?: string; + deptName?: string; + companyName?: string; + categoryName?: string; + levelName?: string; + admissionTime?: Date; + evaluationTime?: Date; + [key: string]: any; +} + +/** + * 供应商选择器组件 + * 用于从系统中选择供应商数据,支持搜索过滤、分页加载、双列表展示 + * + * @param {SupplierSelectorProps} props - 组件属性 + * @returns {React.ReactElement} 供应商选择器组件 + */ +const SupplierSelector: React.FC = ({ + onSelect, + selectedSuppliers: initialSelectedSuppliers = [], + deptList = [], + showDeptFilter = true, + showCompanyFilter = false +}) => { + // 表单实例,用于管理查询条件 + const [form] = Form.useForm(); + + // 待选供应商数据列表 + const [tableListData, setTableListData] = useState([]); + + // 分页信息 + const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 }); + + // 加载状态 + const [loading, setLoading] = useState(false); + + // 左侧待选列表中已选中的项的ID + const [leftSelected, setLeftSelected] = useState([]); + + // 右侧已选列表中选中的项的ID + const [rightSelected, setRightSelected] = useState([]); + + // 最终已选择的供应商列表 + const [chosenSuppliers, setChosenSuppliers] = useState(initialSelectedSuppliers); + + /** + * 监听初始已选供应商变化,更新内部状态 + */ + useEffect(() => { + setChosenSuppliers(initialSelectedSuppliers); + }, [initialSelectedSuppliers]); + + /** + * 合并供应商列表并去重 + * @param {SupplierItem[]} suppliers - 原有的供应商列表 + * @param {SupplierItem[]} selected - 新选择的供应商列表 + * @returns {SupplierItem[]} 合并后的供应商列表,去除重复项 + */ + const filteredData = (suppliers: SupplierItem[], selected: SupplierItem[]) => { + // 创建已有供应商ID的集合,用于快速查找 + const ids = new Set(suppliers.map((item: SupplierItem) => item.id)); + // 过滤出未在原列表中出现的供应商 + const newSelected = selected.filter((item: SupplierItem) => !ids.has(item.id)); + // 合并列表 + return [...suppliers, ...newSelected]; + }; + + /** + * 将左侧选中的供应商移动到右侧已选列表 + */ + const moveToRight = () => { + // 获取左侧选中的供应商数据 + const selected = tableListData.filter((item: SupplierItem) => leftSelected.includes(item.id)); + // 合并到已选列表并去重 + const chosenSuppliersNew = filteredData(chosenSuppliers, selected); + // 更新已选列表 + setChosenSuppliers(chosenSuppliersNew); + // 清空左侧选择状态 + setLeftSelected([]); + // 触发外部回调 + onSelect?.(chosenSuppliersNew); + }; + + /** + * 将右侧选中的供应商从已选列表中移除 + */ + const moveToLeft = () => { + // 过滤掉右侧选中的供应商 + const remaining = chosenSuppliers.filter((item: SupplierItem) => !rightSelected.includes(item.id)); + // 更新已选列表 + setChosenSuppliers(remaining); + // 清空右侧选择状态 + setRightSelected([]); + // 触发外部回调 + onSelect?.(remaining); + }; + + /** + * 获取供应商列表数据 + * @param {any} values - 查询条件 + * @param {number} pageNo - 页码 + * @param {number} pageSize - 每页数量 + */ + const getTableList = async (values: any = {}, pageNo: number = 1, pageSize: number = 10) => { + setLoading(true); + try { + // 整理查询参数 + const params = { + ...values, + pageNo, + pageSize, + deptList: deptList.length > 0 ? deptList : undefined + }; + + // 调用API获取供应商列表 + const response = await getSupplierPage(params); + + if (response && response.code === 200) { + // 请求成功,更新数据和分页信息 + setTableListData(response.data.records || []); + setPagination({ + current: pageNo, + pageSize, + total: response.data.total || 0 + }); + } else { + // 请求失败,显示错误信息 + message.error(response?.message || '获取供应商列表失败'); + + // 使用mock数据作为备用 + setTableListData([ + { id: '1', name: '供应商A', deptName: '采购部', companyName: '公司A', categoryName: '润滑油' }, + { id: '2', name: '供应商B', deptName: '技术部', companyName: '公司B', categoryName: '燃油' }, + { id: '3', name: '供应商C', deptName: '质量部', companyName: '公司C', categoryName: '备件' }, + { id: '4', name: '供应商D', deptName: '采购部', companyName: '公司D', categoryName: '计算机' }, + { id: '5', name: '供应商E', deptName: '技术部', companyName: '公司E', categoryName: '通信设备' }, + ]); + setPagination({ current: 1, pageSize: 10, total: 5 }); + } + } catch (error) { + // 处理异常情况 + console.error('获取供应商列表出错:', error); + message.error('获取供应商列表失败,请稍后重试'); + + // 使用mock数据作为备用 + setTableListData([ + { id: '1', name: '供应商A', deptName: '采购部', companyName: '公司A', categoryName: '润滑油' }, + { id: '2', name: '供应商B', deptName: '技术部', companyName: '公司B', categoryName: '燃油' }, + { id: '3', name: '供应商C', deptName: '质量部', companyName: '公司C', categoryName: '备件' }, + { id: '4', name: '供应商D', deptName: '采购部', companyName: '公司D', categoryName: '计算机' }, + { id: '5', name: '供应商E', deptName: '技术部', companyName: '公司E', categoryName: '通信设备' }, + ]); + setPagination({ current: 1, pageSize: 10, total: 5 }); + } finally { + setLoading(false); + } + }; + + /** + * 组件初始化时加载数据 + */ + useEffect(() => { + const values = form.getFieldsValue(); + getTableList(values, 1, 10); + }, [deptList]); + + /** + * 处理查询表单提交 + * @param {any} values - 表单值 + */ + const handleSearch = (values: any) => { + getTableList(values, 1, pagination.pageSize); + }; + + /** + * 重置查询表单并重新加载数据 + */ + const handleReset = () => { + form.resetFields(); + const values = form.getFieldsValue(); + getTableList(values, 1, pagination.pageSize); + }; + + /** + * 处理表格分页变化 + * @param {any} paginationInfo - 分页信息 + */ + const handleTableChange = (paginationInfo: any) => { + const values = form.getFieldsValue(); + getTableList(values, paginationInfo.current, paginationInfo.pageSize); + }; + + // 表格列定义 + const columns = [ + { + title: '供应商名称', + dataIndex: 'name', + ellipsis: true, + render: (name: string) => ( + + {name} + + ), + }, + { + title: '所属品类', + dataIndex: 'categoryName', + ellipsis: true, + render: (categoryName: string) => ( + + {categoryName || '-'} + + ), + } + ]; + + // 如果显示部门筛选,添加部门列 + if (showDeptFilter) { + columns.push({ + title: '部门', + dataIndex: 'deptName', + ellipsis: true, + render: (deptName: string) => ( + + {deptName || '-'} + + ) + }); + } + + // 如果显示公司名称筛选,添加公司名称列 + if (showCompanyFilter) { + columns.push({ + title: '公司名称', + dataIndex: 'companyName', + ellipsis: true, + render: (companyName: string) => ( + + {companyName || '-'} + + ), + }); + } + + return ( +
+ {/* 查询表单 */} +
+ + + + + {showDeptFilter && ( + + + + )} + + {showCompanyFilter && ( + + + + )} + + + + + + + + + + + + + + {/* 供应商选择区域 */} + + {/* 左侧待选列表 */} +
+
+ 待选供应商 + {pagination.total}项 +
+
+ + + {/* 中间操作按钮 */} + + +
+ 已选供应商 + {chosenSuppliers.length}项 +
+
+ + + + ); +}; + +export default SupplierSelector; diff --git a/src/components/SupplierSelector/index.ts b/src/components/SupplierSelector/index.ts new file mode 100644 index 0000000..eae2eb0 --- /dev/null +++ b/src/components/SupplierSelector/index.ts @@ -0,0 +1,3 @@ +import SupplierSelector from './SupplierSelector'; + +export default SupplierSelector; diff --git a/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResult.tsx b/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResult.tsx index b15bca2..721b42c 100644 --- a/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResult.tsx +++ b/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResult.tsx @@ -190,8 +190,8 @@ const SupplierEvaluateResult: React.FC = () => { }, { title: '评价品类', - dataIndex: 'category', - key: 'category', + dataIndex: 'categoryName', + key: 'categoryName', width: 120, ellipsis: { showTitle: false, diff --git a/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResultInfo.tsx b/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResultInfo.tsx index fb897ca..1fc1665 100644 --- a/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResultInfo.tsx +++ b/src/pages/supplierEvaluateManage/supplierEvaluateResult/supplierEvaluateResultInfo.tsx @@ -212,8 +212,8 @@ const SupplierEvaluateResultInfo: React.FC = () => { }, { title: '品类', - dataIndex: 'category', - key: 'category', + dataIndex: 'categoryName', + key: 'categoryName', width: 120, }, { diff --git a/src/pages/supplierEvaluateManage/supplierTaskManage/components/BasicInfoStep.tsx b/src/pages/supplierEvaluateManage/supplierTaskManage/components/BasicInfoStep.tsx index 725205a..44642b3 100644 --- a/src/pages/supplierEvaluateManage/supplierTaskManage/components/BasicInfoStep.tsx +++ b/src/pages/supplierEvaluateManage/supplierTaskManage/components/BasicInfoStep.tsx @@ -22,7 +22,6 @@ interface TemplateItem { const BasicInfoStep = forwardRef(({ formData, onFormDataChange }, ref) => { const [form] = Form.useForm(); const [templates, setTemplates] = useState([]); - const [selectedCategoryId, setSelectedCategoryId] = useState(undefined); const [loading, setLoading] = useState(false); // 暴露表单方法给父组件 @@ -64,11 +63,6 @@ const BasicInfoStep = forwardRef(({ formData, onFormDat // 初始化表单数据 if (formData) { form.setFieldsValue(formData); - - // 设置已选品类 - if (formData.categoryId) { - setSelectedCategoryId(formData.categoryId); - } } }, []); @@ -78,6 +72,7 @@ const BasicInfoStep = forwardRef(({ formData, onFormDat if (changedValues.templateId) { const template = templates.find((t) => t.id === changedValues.templateId); if (template) { + // 更新品类限制类型 form.setFieldsValue({ categoryLimitation: template.categoryLimitation || '0', }); @@ -87,16 +82,10 @@ const BasicInfoStep = forwardRef(({ formData, onFormDat form.setFieldsValue({ categoryId: undefined, }); - setSelectedCategoryId(undefined); } } } - // 处理品类变更 - if (changedValues.categoryId) { - setSelectedCategoryId(changedValues.categoryId?.[0]); - } - // 默认设置weightStatus为0 const formattedValues = { ...allValues, @@ -122,11 +111,6 @@ const BasicInfoStep = forwardRef(({ formData, onFormDat return categoryLimitation === CategoryLimitationType.LIMITED; }, [form]); - // 处理品类选择变化 - const handleCategoryChange = useCallback((value: string | string[]) => { - const categoryId = Array.isArray(value) ? value[0] : value; - setSelectedCategoryId(categoryId); - }, []); return (
@@ -212,7 +196,7 @@ const BasicInfoStep = forwardRef(({ formData, onFormDat name="categoryId" rules={[{ required: true, message: '请选择品类' }]} > - + )} diff --git a/src/pages/supplierEvaluateManage/supplierTaskManage/components/SupplierSelectStep.tsx b/src/pages/supplierEvaluateManage/supplierTaskManage/components/SupplierSelectStep.tsx index bb8c1a5..f2004e9 100644 --- a/src/pages/supplierEvaluateManage/supplierTaskManage/components/SupplierSelectStep.tsx +++ b/src/pages/supplierEvaluateManage/supplierTaskManage/components/SupplierSelectStep.tsx @@ -1,9 +1,7 @@ -import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; -import { Card, Row, Col, Input, Select, Radio, Table, Button, Space, Pagination, Form } from 'antd'; -import { SearchOutlined, ArrowRightOutlined } from '@ant-design/icons'; +import React, { forwardRef, useImperativeHandle } from 'react'; +import { Card, Form } from 'antd'; import styles from '../supplierTaskManageAdd.less'; - -const { Option } = Select; +import SupplierSelector from '@/components/SupplierSelector'; interface SupplierSelectStepProps { formData: any; @@ -11,28 +9,13 @@ interface SupplierSelectStepProps { } interface SupplierItem { - key: string; - supplierName: string; - socialCreditCode: string; - category: string; + id: string; + name: string; + supplierType: string; + [key: string]: any; } const SupplierSelectStep = forwardRef(({ formData, onFormDataChange }, ref) => { - const [filterForm] = Form.useForm(); - const [categoryKeyword, setCategoryKeyword] = useState(''); - const [selectedCategory, setSelectedCategory] = useState(undefined); - const [hasPaymentLastYear, setHasPaymentLastYear] = useState('是'); - const [department, setDepartment] = useState(undefined); - - const [pendingSuppliers, setPendingSuppliers] = useState([]); - const [selectedSuppliers, setSelectedSuppliers] = useState([]); - - const [pendingKeyword, setPendingKeyword] = useState(''); - const [selectedKeyword, setSelectedKeyword] = useState(''); - - const [pendingSelectedRowKeys, setPendingSelectedRowKeys] = useState([]); - const [selectedSelectedRowKeys, setSelectedSelectedRowKeys] = useState([]); - // 暴露表单方法给父组件 useImperativeHandle(ref, () => ({ validateFields: () => { @@ -41,372 +24,37 @@ const SupplierSelectStep = forwardRef(({ formData, }, getFieldsValue: () => { return { - selectedSuppliers, - supplierIds: selectedSuppliers.map(supplier => ({ id: supplier.key })) + selectedSuppliers: formData.selectedSuppliers || [], + supplierIds: (formData.selectedSuppliers || []).map((supplier: SupplierItem) => ({ id: supplier.id })) }; }, setFieldsValue: (values: any) => { if (values.selectedSuppliers) { - setSelectedSuppliers(values.selectedSuppliers); + onFormDataChange({ + ...formData, + selectedSuppliers: values.selectedSuppliers + }); } }, })); - // 初始化数据 - useEffect(() => { - // 从formData中恢复已选供应商 - if (formData.selectedSuppliers) { - setSelectedSuppliers(formData.selectedSuppliers); - } - - // 初始化筛选表单 - filterForm.setFieldsValue({ - category: selectedCategory, - categoryKeyword: categoryKeyword, - categoryRange: undefined, - hasPaymentLastYear: hasPaymentLastYear, - department: department - }); - - // 模拟获取待选供应商列表 - const mockPendingSuppliers: SupplierItem[] = [ - { key: '1', supplierName: '供应商A', socialCreditCode: '2425322525', category: '润滑油' }, - { key: '2', supplierName: '供应商B', socialCreditCode: '2425322525', category: '燃油' }, - { key: '3', supplierName: '供应商C', socialCreditCode: '2425322525', category: '备件' }, - { key: '4', supplierName: '供应商D', socialCreditCode: '2425322525', category: '润滑油' }, - { key: '5', supplierName: '供应商E', socialCreditCode: '2425322525', category: '燃油' }, - { key: '6', supplierName: '供应商F', socialCreditCode: '2425322525', category: '备件' }, - { key: '7', supplierName: '供应商G', socialCreditCode: '2425322525', category: '润滑油' }, - { key: '8', supplierName: '供应商H', socialCreditCode: '2425322525', category: '燃油' }, - { key: '9', supplierName: '供应商I', socialCreditCode: '2425322525', category: '备件' }, - { key: '10', supplierName: '供应商J', socialCreditCode: '2425322525', category: '计算机' }, - ]; - - // 模拟已选供应商列表 - const mockSelectedSuppliers: SupplierItem[] = [ - { key: '11', supplierName: '供应商A', socialCreditCode: '4636373737', category: '润滑油' }, - { key: '12', supplierName: '供应商B', socialCreditCode: '4636373737', category: '燃油' }, - { key: '13', supplierName: '供应商C', socialCreditCode: '4636373737', category: '备件' }, - { key: '14', supplierName: '供应商D', socialCreditCode: '4636373737', category: '润滑油' }, - { key: '15', supplierName: '供应商E', socialCreditCode: '4636373737', category: '燃油' }, - { key: '16', supplierName: '供应商F', socialCreditCode: '4636373737', category: '备件' }, - { key: '17', supplierName: '供应商G', socialCreditCode: '4636373737', category: '润滑油' }, - { key: '18', supplierName: '供应商H', socialCreditCode: '4636373737', category: '燃油' }, - { key: '19', supplierName: '供应商I', socialCreditCode: '4636373737', category: '备件' }, - { key: '20', supplierName: '供应商J', socialCreditCode: '4636373737', category: '计算机' }, - ]; - - setPendingSuppliers(mockPendingSuppliers); - - // 如果没有从formData中恢复,则使用模拟数据 - if (!formData.selectedSuppliers) { - setSelectedSuppliers(mockSelectedSuppliers); - } - }, [formData]); - - // 更新表单数据 - const updateFormData = (suppliers: SupplierItem[]) => { + // 处理供应商选择 + const handleSupplierSelect = (suppliers: SupplierItem[]) => { onFormDataChange({ + ...formData, selectedSuppliers: suppliers, - supplierIds: suppliers.map(supplier => ({ id: supplier.key })) + supplierIds: suppliers.map(supplier => ({ id: supplier.id })) }); }; - // 处理筛选条件变化 - const handleFilterChange = (changedValues: any, allValues: any) => { - if ('category' in changedValues) { - setSelectedCategory(changedValues.category); - } - if ('categoryKeyword' in changedValues) { - setCategoryKeyword(changedValues.categoryKeyword); - } - if ('hasPaymentLastYear' in changedValues) { - setHasPaymentLastYear(changedValues.hasPaymentLastYear); - } - if ('department' in changedValues) { - setDepartment(changedValues.department); - } - - // 这里可以添加筛选逻辑,根据筛选条件更新待选供应商列表 - }; - - // 处理添加供应商 - const handleAddSuppliers = () => { - if (pendingSelectedRowKeys.length === 0) return; - - // 找出选中的供应商 - const suppliersToAdd = pendingSuppliers.filter(item => - pendingSelectedRowKeys.includes(item.key) - ); - - // 更新已选供应商列表 - const newSelectedSuppliers = [...selectedSuppliers, ...suppliersToAdd]; - setSelectedSuppliers(newSelectedSuppliers); - - // 从待选列表中移除 - const newPendingSuppliers = pendingSuppliers.filter(item => - !pendingSelectedRowKeys.includes(item.key) - ); - setPendingSuppliers(newPendingSuppliers); - - // 清空选中状态 - setPendingSelectedRowKeys([]); - - // 更新表单数据 - updateFormData(newSelectedSuppliers); - }; - - // 处理移除供应商 - const handleRemoveSuppliers = () => { - if (selectedSelectedRowKeys.length === 0) return; - - // 找出选中的供应商 - const suppliersToRemove = selectedSuppliers.filter(item => - selectedSelectedRowKeys.includes(item.key) - ); - - // 更新待选供应商列表 - const newPendingSuppliers = [...pendingSuppliers, ...suppliersToRemove]; - setPendingSuppliers(newPendingSuppliers); - - // 从已选列表中移除 - const newSelectedSuppliers = selectedSuppliers.filter(item => - !selectedSelectedRowKeys.includes(item.key) - ); - setSelectedSuppliers(newSelectedSuppliers); - - // 清空选中状态 - setSelectedSelectedRowKeys([]); - - // 更新表单数据 - updateFormData(newSelectedSuppliers); - }; - - // 过滤待选供应商 - const filteredPendingSuppliers = pendingSuppliers.filter(item => { - // 按关键词过滤 - const matchKeyword = pendingKeyword ? - (item.supplierName.includes(pendingKeyword) || - item.socialCreditCode.includes(pendingKeyword)) : true; - - return matchKeyword; - }); - - // 过滤已选供应商 - const filteredSelectedSuppliers = selectedSuppliers.filter(item => { - // 按关键词过滤 - const matchKeyword = selectedKeyword ? - (item.supplierName.includes(selectedKeyword) || - item.socialCreditCode.includes(selectedKeyword)) : true; - - return matchKeyword; - }); - - // 表格列定义 - const columns = [ - { - title: '供应商名称', - dataIndex: 'supplierName', - key: 'supplierName', - }, - { - title: '统一社会信用代码', - dataIndex: 'socialCreditCode', - key: 'socialCreditCode', - }, - { - title: '准入品类', - dataIndex: 'category', - key: 'category', - } - ]; - - // 待选表格行选择配置 - const pendingRowSelection = { - selectedRowKeys: pendingSelectedRowKeys, - onChange: (selectedRowKeys: React.Key[]) => { - setPendingSelectedRowKeys(selectedRowKeys); - } - }; - - // 已选表格行选择配置 - const selectedRowSelection = { - selectedRowKeys: selectedSelectedRowKeys, - onChange: (selectedRowKeys: React.Key[]) => { - setSelectedSelectedRowKeys(selectedRowKeys); - } - }; - - // 部门选项 - const departmentOptions = [ - { value: '1', label: '采购部' }, - { value: '2', label: '技术部' }, - { value: '3', label: '质量部' }, - { value: '4', label: '生产部' }, - ]; - - // 类别选项 - const categoryOptions = [ - { value: '润滑油', label: '润滑油' }, - { value: '燃油', label: '燃油' }, - { value: '备件', label: '备件' }, - { value: '计算机', label: '计算机' }, - ]; - return (
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - 2/50项} - > -
- } - value={pendingKeyword} - onChange={e => setPendingKeyword(e.target.value)} - allowClear - /> -
-
-
- -
- - - - - - 2/50项} - > -
- } - value={selectedKeyword} - onChange={e => setSelectedKeyword(e.target.value)} - allowClear - /> -
-
-
- -
- - - ); }); diff --git a/src/pages/supplierEvaluateManage/supplierTaskManage/supplierTaskManageAdd.tsx b/src/pages/supplierEvaluateManage/supplierTaskManage/supplierTaskManageAdd.tsx index fa8990a..11f24f4 100644 --- a/src/pages/supplierEvaluateManage/supplierTaskManage/supplierTaskManageAdd.tsx +++ b/src/pages/supplierEvaluateManage/supplierTaskManage/supplierTaskManageAdd.tsx @@ -11,7 +11,7 @@ import styles from './supplierTaskManageAdd.less'; const { Step } = Steps; const SupplierTaskManageAdd: React.FC = () => { - const [currentStep, setCurrentStep] = useState(0); + const [currentStep, setCurrentStep] = useState(1); const [loading, setLoading] = useState(false); const [formData, setFormData] = useState>({}); diff --git a/src/servers/api/supplier.ts b/src/servers/api/supplier.ts new file mode 100644 index 0000000..245b7a6 --- /dev/null +++ b/src/servers/api/supplier.ts @@ -0,0 +1,71 @@ +import request from '@/utils/request'; + +/** + * 获取供应商基础信息列表 + * @deprecated 请使用 getSupplierPage 替代 + */ +export async function getSupplierBaseList(params: any) { + return request('/api/supplier/base/list', { + method: 'GET', + params, + }); +} + +/** + * 获取供应商分页列表 - 对接/coscoSupplierBase/getSupplierPage接口 + * @param params 查询参数,包含供应商名称、部门ID等筛选条件以及分页信息 + */ +export async function getSupplierPage(params: { + name?: string; // 供应商名称 + deptId?: string; // 部门ID + deptName?: string; // 部门名称 + companyName?: string; // 公司名称 + categoryName?: string; // 所属品类 + levelName?: string; // 评价等级 + blackListDept?: string[]; // 黑名单部门列表 + deptList?: string[]; // 查询部门列表 + pageNo?: number; // 页码 + pageSize?: number; // 每页条数 + [key: string]: any; +}) { + return request('/coscoSupplierBase/getSupplierPage', { + method: 'POST', + data: { + ...params, + basePageRequest: { + pageNo: params.pageNo || 1, + pageSize: params.pageSize || 10 + } + }, + }); +} + +// 获取供应商详情 +export async function getSupplierDetail(id: string) { + return request(`/api/supplier/${id}`, { + method: 'GET', + }); +} + +// 获取供应商品类信息 +export async function getSupplierCategories(supplierId: string) { + return request(`/api/supplier/${supplierId}/categories`, { + method: 'GET', + }); +} + +// 获取可选供应商列表 +export async function getSelectableSuppliers(params: any) { + return request('/api/supplier/selectable', { + method: 'GET', + params, + }); +} + +// 根据供应商ID批量获取供应商信息 +export async function getSuppliersByIds(ids: string[]) { + return request('/api/supplier/batch', { + method: 'POST', + data: { ids }, + }); +}