367 lines
12 KiB
TypeScript
367 lines
12 KiB
TypeScript
import React, { useState, useEffect, forwardRef, useImperativeHandle, useRef } from 'react';
|
||
import { Card, Button, Space, Form } from 'antd';
|
||
import styles from '../supplierAnnualTaskManageAdd.less';
|
||
import {
|
||
SupplierTable,
|
||
BatchEvaluatorModal,
|
||
SupplierEvaluatorModal,
|
||
WeightSettingModal,
|
||
} from './EvaluatorComponents';
|
||
import { ModalMode } from '@/servers/types/evaluator';
|
||
import type { PersonnelItem, SupplierItem } from '@/servers/types/evaluator';
|
||
import type { DeptWeightItem } from '@/servers/dao/supplierEvaluateTask';
|
||
import type { Dispatch } from 'umi';
|
||
import { connect } from 'umi';
|
||
import type { SupplierTaskModelState } from '@/models/supplierAnnualTaskManage';
|
||
|
||
/**
|
||
* 组件接收的Props接口
|
||
* supplierAnnualTaskManage: Dva model 状态
|
||
* dispatch: Dva 的 dispatch 函数,用于触发 action
|
||
* innerRef: 内部 ref 用于暴露方法给父组件
|
||
*/
|
||
interface EvaluatorSelectStepProps {
|
||
supplierAnnualTaskManage: SupplierTaskModelState;
|
||
dispatch: Dispatch;
|
||
innerRef?: any; // 使用 innerRef 作为属性名
|
||
}
|
||
|
||
/**
|
||
* 评价人员选择步骤组件
|
||
* 主要功能:选择供应商评价人员,设置评分单位权重
|
||
* 数据流转:
|
||
* 1. 从上一步获取供应商数据(通过 model.taskFormData)
|
||
* 2. 组织评价人员列表并维护到本地状态
|
||
* 3. 通过 dispatch 将更新的数据同步回 model
|
||
*/
|
||
const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
|
||
const { supplierAnnualTaskManage, dispatch, innerRef } = props;
|
||
|
||
// 从 model 获取表单数据,避免通过 props 层层传递
|
||
const { taskFormData, mode } = supplierAnnualTaskManage;
|
||
|
||
// 选中的供应商行的key列表,用于批量操作
|
||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||
|
||
// 供应商列表数据,包含评价人员信息(从Dva model获取初始数据,维护在本地状态)
|
||
const [suppliers, setSuppliers] = useState<SupplierItem[]>([]);
|
||
|
||
// 批量选择模态框的可见性控制
|
||
const [batchSelectModalVisible, setBatchSelectModalVisible] = useState(false);
|
||
|
||
// 权重设置模态框的可见性控制
|
||
const [weightSettingModalVisible, setWeightSettingModalVisible] = useState(false);
|
||
|
||
// 评价人员选择/查看模态框的可见性控制
|
||
const [evaluatorModalVisible, setEvaluatorModalVisible] = useState(false);
|
||
|
||
// 当前操作的供应商对象,用于评价人员的选择和查看
|
||
const [currentSupplier, setCurrentSupplier] = useState<SupplierItem | null>(null);
|
||
|
||
// 模态框模式:SELECT(选择模式) 或 VIEW(查看模式)
|
||
const [modalMode, setModalMode] = useState<ModalMode>(ModalMode.SELECT);
|
||
|
||
// 权重单位列表,根据评价人员部门动态生成
|
||
const [taskDeptWeightList, setTaskDeptWeightList] = useState<DeptWeightItem[]>([]);
|
||
|
||
// 表单实例,用于权重设置
|
||
const [form] = Form.useForm();
|
||
const [filterUserIds, setFilterUserIds] = useState<string[]>([]);
|
||
useEffect(() => {
|
||
if (mode === 'division' && taskFormData.userList && taskFormData.userList.length > 0) {
|
||
const filterUserIdsaa = taskFormData.userList
|
||
.map((user: PersonnelItem) => (user.isSelected === true ? user.id : null))
|
||
.filter((id: string | null) => id !== null);
|
||
setFilterUserIds(filterUserIdsaa);
|
||
}
|
||
}, [mode, taskFormData.userList]);
|
||
/**
|
||
* 暴露表单方法给父组件
|
||
* 包含验证、获取和设置表单数据的方法
|
||
*/
|
||
useImperativeHandle(innerRef, () => ({
|
||
validateFields: () => {
|
||
// 自定义验证逻辑
|
||
if (suppliers.length === 0) {
|
||
return Promise.reject('请至少添加一个供应商');
|
||
}
|
||
|
||
// 检查是否每个供应商都有评价人员
|
||
const hasNoEvaluator = suppliers.some(
|
||
(supplier) => !supplier.evaluators || supplier.evaluators.length === 0,
|
||
);
|
||
|
||
if (hasNoEvaluator) {
|
||
return Promise.reject('存在未分配评价人员的供应商');
|
||
}
|
||
|
||
return Promise.resolve();
|
||
}
|
||
}));
|
||
|
||
/**
|
||
* 从上一步获取供应商数据
|
||
* 使用 useEffect 监听 taskFormData 变化,确保任何来自 model 的数据变更都能被捕获
|
||
*/
|
||
useEffect(() => {
|
||
// 从Dva model中获取上一步选择的供应商数据
|
||
if (taskFormData.selectedSuppliers && taskFormData.selectedSuppliers.length > 0) {
|
||
// 转换上一步的供应商数据,添加评价人员数量字段
|
||
const suppliersWithEvaluators = taskFormData.selectedSuppliers.map(
|
||
(supplier: SupplierItem) => {
|
||
// 确保evaluators字段存在且为数组
|
||
const evaluators = supplier.evaluators || [];
|
||
return {
|
||
...supplier,
|
||
userDept: supplier.userDept || '采购部', // 设置默认部门
|
||
evaluatorCount: evaluators.length,
|
||
evaluators: evaluators,
|
||
};
|
||
},
|
||
);
|
||
|
||
// 更新本地供应商状态
|
||
setSuppliers(suppliersWithEvaluators);
|
||
} else {
|
||
// 没有选择供应商,清空供应商列表
|
||
setSuppliers([]);
|
||
}
|
||
|
||
}, [taskFormData]); // 依赖于 taskFormData,当 model 数据变化时重新计算
|
||
|
||
|
||
/**
|
||
* 更新表单数据
|
||
* 将本地状态同步到 Dva model
|
||
* @param updatedData 要更新的部分数据
|
||
*/
|
||
const updateFormData = (updatedData: any) => {
|
||
// 结构 更新数据中的suppliersWithEvaluators
|
||
const { suppliersWithEvaluators }: { suppliersWithEvaluators: SupplierItem[] } = updatedData;
|
||
// 构建供应商ID列表
|
||
const supplierIds = suppliersWithEvaluators.map((supplier) => ({
|
||
suppliedId: supplier.id,
|
||
userIds: supplier.evaluators?.map((e: PersonnelItem) => e.id) || [],
|
||
}));
|
||
|
||
// 构建userList 并去重,确保保留 isSelected 为 true 的对象
|
||
const userMap = new Map();
|
||
suppliersWithEvaluators
|
||
.flatMap((s) => s.evaluators || [])
|
||
.forEach((user) => {
|
||
// 如果已存在此ID的用户且当前用户isSelected为true,或者Map中不存在此用户,则更新/添加
|
||
if (!userMap.has(user.id) || user.isSelected) {
|
||
userMap.set(user.id, user);
|
||
}
|
||
});
|
||
|
||
|
||
// 通过dispatch更新model中的数据
|
||
// 这是组件与Dva model交互的关键
|
||
dispatch({
|
||
type: 'supplierAnnualTaskManage/updateFormData', // action类型
|
||
payload: {
|
||
// action数据
|
||
...updatedData,
|
||
supplierIds,
|
||
selectedSuppliers: suppliersWithEvaluators,
|
||
},
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 处理批量选择按钮点击事件
|
||
* 打开批量选择评价人员模态框
|
||
*/
|
||
const handleBatchSelect = () => {
|
||
if (selectedRowKeys.length === 0) return;
|
||
setBatchSelectModalVisible(true);
|
||
};
|
||
/**
|
||
* 处理选择评价人员按钮点击事件
|
||
* 打开评价人员选择模态框
|
||
* @param supplier 当前选中的供应商
|
||
*/
|
||
const handleSelectEvaluators = (supplier: SupplierItem) => {
|
||
setCurrentSupplier(supplier);
|
||
setModalMode(ModalMode.SELECT);
|
||
setEvaluatorModalVisible(true);
|
||
};
|
||
|
||
/**
|
||
* 处理查看评价人员按钮点击事件
|
||
* 打开评价人员查看模态框
|
||
* @param supplier 当前选中的供应商
|
||
*/
|
||
const handleViewEvaluators = (supplier: SupplierItem) => {
|
||
// 查找完整的供应商数据(包括evaluators)
|
||
const fullSupplier = suppliers.find((s) => s.id === supplier.id);
|
||
if (fullSupplier) {
|
||
setCurrentSupplier(fullSupplier);
|
||
} else {
|
||
setCurrentSupplier(supplier);
|
||
}
|
||
|
||
setModalMode(ModalMode.VIEW);
|
||
setEvaluatorModalVisible(true);
|
||
};
|
||
|
||
/**
|
||
* 处理评价人员选择确认
|
||
* 更新供应商的评价人员列表并同步到 Dva model
|
||
* @param selectedEvaluators 选中的评价人员列表
|
||
*/
|
||
const handleEvaluatorSelect = (selectedEvaluators: PersonnelItem[]) => {
|
||
if (!currentSupplier) return;
|
||
// 更新当前供应商的评价人员列表
|
||
const updatedSuppliers = suppliers.map((supplier) => {
|
||
if (supplier.id === currentSupplier.id) {
|
||
const updated = {
|
||
...supplier,
|
||
evaluators: selectedEvaluators,
|
||
evaluatorCount: selectedEvaluators.length,
|
||
};
|
||
return updated;
|
||
}
|
||
return supplier;
|
||
});
|
||
|
||
// 更新本地状态
|
||
setSuppliers(updatedSuppliers);
|
||
|
||
// 同步到Dva model
|
||
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
|
||
|
||
// 关闭模态框
|
||
setEvaluatorModalVisible(false);
|
||
};
|
||
|
||
/**
|
||
* 处理批量选择评价人员确认
|
||
* 批量更新供应商的评价人员列表并同步到 Dva model
|
||
* @param selectedEvaluators 选中的评价人员列表
|
||
*/
|
||
const handleBatchEvaluatorSelect = (selectedEvaluators: PersonnelItem[]) => {
|
||
if (selectedRowKeys.length === 0) return;
|
||
|
||
// 更新所有选中供应商的评价人员列表
|
||
const updatedSuppliers = suppliers.map((supplier) => {
|
||
if (selectedRowKeys.includes(supplier.id)) {
|
||
return {
|
||
...supplier,
|
||
evaluators: selectedEvaluators,
|
||
evaluatorCount: selectedEvaluators.length,
|
||
};
|
||
}
|
||
return supplier;
|
||
});
|
||
|
||
// 更新本地状态
|
||
setSuppliers(updatedSuppliers);
|
||
|
||
// 同步到Dva model
|
||
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
|
||
|
||
// 关闭模态框
|
||
setBatchSelectModalVisible(false);
|
||
};
|
||
|
||
/**
|
||
* 处理删除供应商
|
||
* 从供应商列表中删除指定供应商并同步到 Dva model
|
||
* @param key 供应商ID
|
||
*/
|
||
const handleDeleteSupplier = (key: string) => {
|
||
// 过滤掉要删除的供应商
|
||
const updatedSuppliers = suppliers.filter((item) => item.id !== key);
|
||
|
||
// 更新本地状态
|
||
setSuppliers(updatedSuppliers);
|
||
|
||
// 同步到Dva model
|
||
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
|
||
|
||
// 更新选中行,移除已删除的供应商
|
||
setSelectedRowKeys((prevKeys) => prevKeys.filter((k) => k !== key));
|
||
};
|
||
|
||
// 渲染组件
|
||
return (
|
||
<div className={styles.evaluatorSelectStep}>
|
||
<Card title="选择年审人员" bordered={false} className="inner-card">
|
||
{/* 工具栏区域 */}
|
||
{mode !== 'division' && (
|
||
<div className={styles.toolbar}>
|
||
<Space>
|
||
<Button
|
||
type="primary"
|
||
onClick={handleBatchSelect}
|
||
disabled={selectedRowKeys.length === 0}
|
||
>
|
||
批量选择年审人员
|
||
</Button>
|
||
</Space>
|
||
</div>
|
||
)}
|
||
|
||
{/* 供应商表格区域 */}
|
||
{suppliers.length === 0 ? (
|
||
<div style={{ textAlign: 'center', padding: '30px 0', color: '#999' }}>
|
||
请先在上一步选择供应商
|
||
</div>
|
||
) : (
|
||
<SupplierTable
|
||
suppliers={suppliers}
|
||
mode={mode}
|
||
selectedRowKeys={selectedRowKeys}
|
||
onSelectChange={setSelectedRowKeys}
|
||
onViewEvaluators={handleViewEvaluators}
|
||
onSelectEvaluators={handleSelectEvaluators}
|
||
onDeleteSupplier={handleDeleteSupplier}
|
||
/>
|
||
)}
|
||
|
||
{/* 批量选择年审人员弹窗 */}
|
||
<BatchEvaluatorModal
|
||
visible={batchSelectModalVisible}
|
||
onCancel={() => setBatchSelectModalVisible(false)}
|
||
filter={mode === 'division'}
|
||
filterUserIds={filterUserIds}
|
||
onSelect={handleBatchEvaluatorSelect}
|
||
/>
|
||
|
||
{/* 单个供应商年审人员弹窗 */}
|
||
<SupplierEvaluatorModal
|
||
visible={evaluatorModalVisible}
|
||
onCancel={() => setEvaluatorModalVisible(false)}
|
||
filter={mode === 'division'}
|
||
filterUserIds={filterUserIds}
|
||
onSelect={handleEvaluatorSelect}
|
||
currentSupplier={currentSupplier}
|
||
mode={modalMode}
|
||
/>
|
||
|
||
</Card>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
/**
|
||
* 连接 Dva model
|
||
* 将 model 中的状态映射到组件 props
|
||
*/
|
||
const ConnectedComponent = connect(
|
||
({ supplierAnnualTaskManage }: { supplierAnnualTaskManage: SupplierTaskModelState }) => ({
|
||
supplierAnnualTaskManage,
|
||
}),
|
||
)(EvaluatorSelectStepComponent);
|
||
|
||
/**
|
||
* 外层转发 ref 到 innerRef
|
||
*/
|
||
const EvaluatorSelectStep = forwardRef((props: any, ref) => (
|
||
<ConnectedComponent {...props} innerRef={ref} />
|
||
));
|
||
|
||
export default EvaluatorSelectStep;
|