Files
fe_supplier_frontend/src/pages/supplierEvaluateManage/supplierTaskManage/components/DivisionStep.tsx

631 lines
19 KiB
TypeScript
Raw Normal View History

2025-06-26 12:06:47 +08:00
import React, {
useState,
useEffect,
forwardRef,
useImperativeHandle,
useMemo,
useCallback,
useRef,
} from 'react';
import {
Card,
Table,
Tag,
Switch,
Space,
Button,
message,
Modal,
Radio,
Checkbox,
Row,
Col,
Spin,
} from 'antd';
2025-06-24 18:58:43 +08:00
import type { PersonnelItem } from '@/servers/types/evaluator';
import type { ColumnsType } from 'antd/es/table';
2025-06-24 20:32:55 +08:00
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable';
import { getTemplateDetail } from '@/servers/api/supplierEvaluate';
2025-06-26 12:06:47 +08:00
import type { TaskAddRequest } from '@/servers/types/supplierEvaluateTask';
2025-06-24 18:58:43 +08:00
// 评价指标类型定义
interface IndicatorItem {
id: string;
name: string;
description: string;
}
// 组件接收的Props定义
interface DivisionStepProps {
2025-06-26 12:06:47 +08:00
formData: Partial<TaskAddRequest>;
onFormDataChange?: (values: Partial<TaskAddRequest>) => void;
2025-06-24 18:58:43 +08:00
}
// 评价方式枚举
2025-06-24 20:32:55 +08:00
// 注意type值是根据用户是否关联了指标自动计算的不是由用户直接选择的
// 默认为0(按评价单)当用户关联了指标则为1(按指标)
2025-06-24 18:58:43 +08:00
enum EvaluateType {
2025-06-24 20:32:55 +08:00
ALL = 0, // 按评价单评价(全部指标)
INDICATOR = 1, // 按指标评价(部分指标)
2025-06-24 18:58:43 +08:00
}
const DivisionStep = forwardRef<any, DivisionStepProps>(({ formData, onFormDataChange }, ref) => {
// 从上一步获取的评价人员列表
const [evaluators, setEvaluators] = useState<PersonnelItem[]>([]);
// 评价人员指标分配数据
2025-06-26 12:06:47 +08:00
const indicatorAssignments = useRef<{
2025-06-24 18:58:43 +08:00
[userId: string]: {
type: EvaluateType;
indicatorIds: string[];
};
}>({});
2025-06-26 12:06:47 +08:00
// const [indicatorAssignments, setIndicatorAssignments] = useState<{
// [userId: string]: {
// type: EvaluateType;
// indicatorIds: string[];
// };
// }>({});
2025-06-24 18:58:43 +08:00
// 选中的行keys
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
2025-06-24 20:32:55 +08:00
// 指标列表 - 不再直接使用mockIndicators而是从templateData派生
const [indicators, setIndicators] = useState<IndicatorItem[]>([]);
2025-06-24 18:58:43 +08:00
2025-06-24 20:32:55 +08:00
// 评价指标模板查看弹窗可见性
const [templateViewModalVisible, setTemplateViewModalVisible] = useState(false);
2025-06-24 18:58:43 +08:00
2025-06-24 20:32:55 +08:00
// 批量指标设置弹窗可见性
const [batchTemplateModalVisible, setBatchTemplateModalVisible] = useState(false);
2025-06-24 18:58:43 +08:00
// 批量选择的指标
const [batchSelectedIndicators, setBatchSelectedIndicators] = useState<string[]>([]);
2025-06-24 20:32:55 +08:00
// 批量选择的模板项
const [batchSelectedTemplateItems, setBatchSelectedTemplateItems] = useState<any[]>([]);
// 当前查看的用户ID
const [currentUserId, setCurrentUserId] = useState<string>('');
// 模板数据
const [templateData, setTemplateData] = useState<any[]>([]);
// 加载状态
const [loading, setLoading] = useState<boolean>(false);
// 选中的指标项
const [selectedTemplateItems, setSelectedTemplateItems] = useState<any[]>([]);
2025-06-26 12:06:47 +08:00
// 查看指标分工弹窗可见性
const [viewModalVisible, setViewModalVisible] = useState(false);
// 查看模式下的过滤后指标数据
const [filteredIndicators, setFilteredIndicators] = useState<any[]>([]);
// 统一获取用户指标ID的函数
const getUserIndicatorIds = useCallback((userId: string) => {
if (!userId) return [];
const assignment = indicatorAssignments.current[userId];
if (!assignment) return [];
// 如果是按评价单评价(全部指标),返回空数组
if (assignment.type == EvaluateType.ALL) {
return [];
}
// 如果是按指标评价返回指标ID列表
return assignment.indicatorIds || [];
}, []);
// 获取当前用户的已分配指标ID
const getCurrentUserSelectedIds = useCallback(() => {
// 使用统一的getUserIndicatorIds函数获取当前用户的指标ID
return getUserIndicatorIds(currentUserId);
}, [currentUserId, getUserIndicatorIds]);
// 根据指标ID过滤模板数据
const filterTemplateDataByIds = useCallback((data: any[], indicatorIds: string[]) => {
// 如果indicatorIds为空表示显示所有模板数据(按评价单评价)
if (!indicatorIds || indicatorIds.length === 0) {
return data;
}
// 按指标ID过滤
const filtered = [];
for (const stItem of data) {
const ndItems = [];
if (stItem.indicatorNdList) {
for (const ndItem of stItem.indicatorNdList) {
const matched = indicatorIds.some((id) => String(id) === String(ndItem.id));
if (matched) {
ndItems.push(ndItem);
}
}
}
if (ndItems.length > 0) {
filtered.push({
...stItem,
indicatorNdList: ndItems,
});
}
}
return filtered;
}, []);
2025-06-24 20:32:55 +08:00
// 获取模板详情 先写死 "1937123786334322688" 省的一步一步操作
2025-06-26 12:06:47 +08:00
const fetchTemplateDetail = async (templateId: string) => {
2025-06-24 20:32:55 +08:00
if (!templateId) return;
try {
setLoading(true);
const res = await getTemplateDetail(templateId);
if (res.success && res.data) {
// 直接设置指标数据,无需转换
if (res.data.indicatorStList && res.data.indicatorStList.length > 0) {
setTemplateData(res.data.indicatorStList);
// 更新指标列表
const newIndicators = res.data.indicatorStList.map((item: any) => ({
id: item.id,
name: item.baseIndicator,
description: item.descIndicator || '',
}));
// 更新indicators状态
setIndicators(newIndicators);
}
} else {
message.error(res.message || '获取模板详情失败');
}
} catch (error) {
console.error('获取模板详情失败:', error);
message.error('获取模板详情失败');
} finally {
setLoading(false);
}
};
// 监听templateId变化获取模板详情
useEffect(() => {
2025-06-26 12:06:47 +08:00
fetchTemplateDetail(formData.templateId as string);
2025-06-24 20:32:55 +08:00
}, []);
2025-06-24 18:58:43 +08:00
// 处理行选择变化
const handleSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
// 打开指标分工弹窗
const handleOpenDivisionModal = () => {
if (selectedRowKeys.length === 0) {
message.warning('请先选择评价人员');
return;
}
2025-06-24 20:32:55 +08:00
// 直接显示批量模板选择弹窗
setBatchTemplateModalVisible(true);
// 重置已选中的模板项
setBatchSelectedTemplateItems([]);
2025-06-24 18:58:43 +08:00
};
2025-06-24 20:32:55 +08:00
// 处理批量模板指标选择
const handleBatchTemplateItemsSelect = (selectedItems: any[]) => {
setBatchSelectedTemplateItems(selectedItems);
2025-06-24 18:58:43 +08:00
};
2025-06-24 20:32:55 +08:00
// 关闭批量模板选择弹窗
const handleCloseBatchTemplateModal = () => {
setBatchTemplateModalVisible(false);
2025-06-24 18:58:43 +08:00
};
// 批量设置指标分工
const handleBatchSetDivision = () => {
// 获取选中的评价人员
2025-06-26 12:06:47 +08:00
const selectedEvaluators = evaluators.filter((evaluator) =>
selectedRowKeys.includes(evaluator.id),
2025-06-24 18:58:43 +08:00
);
2025-06-24 20:32:55 +08:00
// 提取所有选中指标的ID
const selectedIndicatorIds: string[] = [];
// 从选中的模板项中提取所有指标ID
2025-06-26 12:06:47 +08:00
batchSelectedTemplateItems.forEach((stItem) => {
2025-06-24 20:32:55 +08:00
// 添加二级指标ID
if (stItem.indicatorNdList && stItem.indicatorNdList.length > 0) {
stItem.indicatorNdList.forEach((ndItem: any) => {
selectedIndicatorIds.push(ndItem.id);
});
}
});
2025-06-24 18:58:43 +08:00
// 更新指标分配数据
2025-06-26 12:06:47 +08:00
const newAssignments = { ...indicatorAssignments.current };
2025-06-24 18:58:43 +08:00
2025-06-26 12:06:47 +08:00
selectedEvaluators.forEach((evaluator) => {
2025-06-24 18:58:43 +08:00
newAssignments[evaluator.id] = {
2025-06-24 20:32:55 +08:00
// 评价类型如果用户关联了指标则为1(按指标)否则为0(按评价单)
type: selectedIndicatorIds.length > 0 ? EvaluateType.INDICATOR : EvaluateType.ALL,
indicatorIds: selectedIndicatorIds,
2025-06-24 18:58:43 +08:00
};
});
2025-06-26 12:06:47 +08:00
indicatorAssignments.current = newAssignments;
2025-06-24 20:32:55 +08:00
setBatchTemplateModalVisible(false);
2025-06-24 18:58:43 +08:00
message.success(`已为${selectedRowKeys.length}名评价人员设置分工`);
};
// 处理单个评价人员的指标分工
const handleAssignIndicators = (userId: string) => {
2025-06-24 20:32:55 +08:00
setCurrentUserId(userId);
// 重置已选中的指标项
setSelectedTemplateItems([]);
// 打开模态框
setTemplateViewModalVisible(true);
};
// 关闭模板查看模态框
const handleCloseTemplateViewModal = () => {
setTemplateViewModalVisible(false);
};
// 处理模板指标选择
const handleTemplateItemsSelect = (selectedItems: any[]) => {
2025-06-26 12:06:47 +08:00
console.log(selectedItems);
2025-06-24 20:32:55 +08:00
setSelectedTemplateItems(selectedItems);
};
// 保存指标分配
const handleSaveIndicatorAssignment = () => {
if (!currentUserId) {
message.warning('未选择评价人员');
return;
}
// 提取所有选中指标的ID
const selectedIndicatorIds: string[] = [];
// 从选中的模板项中提取所有指标ID
2025-06-26 12:06:47 +08:00
selectedTemplateItems.forEach((stItem) => {
2025-06-24 20:32:55 +08:00
// 添加二级指标ID
if (stItem.indicatorNdList && stItem.indicatorNdList.length > 0) {
stItem.indicatorNdList.forEach((ndItem: any) => {
selectedIndicatorIds.push(ndItem.id);
});
}
2025-06-24 18:58:43 +08:00
});
2025-06-24 20:32:55 +08:00
// 更新指标分配
2025-06-26 12:06:47 +08:00
const newAssignments = { ...indicatorAssignments.current };
2025-06-24 20:32:55 +08:00
newAssignments[currentUserId] = {
// 评价类型如果用户关联了指标则为1(按指标)否则为0(按评价单)
type: selectedIndicatorIds.length > 0 ? EvaluateType.INDICATOR : EvaluateType.ALL,
indicatorIds: selectedIndicatorIds,
};
2025-06-26 12:06:47 +08:00
indicatorAssignments.current = newAssignments;
2025-06-24 20:32:55 +08:00
setTemplateViewModalVisible(false);
message.success('已设置评价人员指标分工');
2025-06-24 18:58:43 +08:00
};
// 查看评价人员的指标分工
const handleViewAssignment = (userId: string) => {
2025-06-26 12:06:47 +08:00
const assignment = indicatorAssignments.current[userId];
2025-06-24 18:58:43 +08:00
if (!assignment) {
message.info('该评价人员尚未设置分工');
return;
}
2025-06-26 12:06:47 +08:00
setCurrentUserId(userId);
setLoading(true);
2025-06-24 18:58:43 +08:00
2025-06-26 12:06:47 +08:00
// 获取该评价人员的指标ID
const indicatorIds = getUserIndicatorIds(userId);
// 过滤模板数据
const filtered = filterTemplateDataByIds(templateData, indicatorIds);
setFilteredIndicators(filtered);
setLoading(false);
setViewModalVisible(true);
};
// 关闭查看模态框
const handleCloseViewModal = () => {
setViewModalVisible(false);
2025-06-24 18:58:43 +08:00
};
// 删除评价人员
const handleRemoveEvaluator = (userId: string) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除该评价人员吗?',
okText: '确定',
cancelText: '取消',
onOk: () => {
// 更新评价人员列表
2025-06-26 12:06:47 +08:00
setEvaluators((prev) => prev.filter((e) => e.id !== userId));
2025-06-24 18:58:43 +08:00
// 更新指标分配数据
2025-06-26 12:06:47 +08:00
const newAssignments = { ...indicatorAssignments.current };
2025-06-24 18:58:43 +08:00
delete newAssignments[userId];
2025-06-26 12:06:47 +08:00
indicatorAssignments.current = newAssignments;
2025-06-24 18:58:43 +08:00
message.success('已删除评价人员');
},
});
};
// 初始化从formData中提取指标分配数据
useEffect(() => {
2025-06-26 12:06:47 +08:00
if (formData.indicatorList && formData.indicatorList.length > 0) {
2025-06-24 18:58:43 +08:00
// 如果已有指标分配数据,直接使用
const assignments: any = {};
formData.indicatorList.forEach((item: any) => {
assignments[item.userId] = {
type: item.type,
indicatorIds: item.indicatorIds || [],
};
});
2025-06-26 12:06:47 +08:00
indicatorAssignments.current = assignments;
2025-06-24 18:58:43 +08:00
}
}, [formData.indicatorList]);
// 从上一步获取评价人员列表 - 避免频繁更新
useEffect(() => {
if (!formData.suppliersWithEvaluators) return;
// 从所有供应商中提取评价人员列表
const allEvaluators: PersonnelItem[] = [];
formData.suppliersWithEvaluators.forEach((supplier: any) => {
if (supplier.evaluators && supplier.evaluators.length > 0) {
supplier.evaluators.forEach((evaluator: PersonnelItem) => {
// 检查是否已存在(避免重复)
2025-06-26 12:06:47 +08:00
if (!allEvaluators.some((e) => e.id === evaluator.id)) {
2025-06-24 18:58:43 +08:00
allEvaluators.push({
...evaluator,
// 添加单位和员工编号,假设这些字段可能不存在
company: evaluator.company || supplier.supplierName || '未知单位',
employeeNumber: evaluator.employeeNumber || `EMP${evaluator.id.slice(-4)}`,
department: evaluator.department || '未知部门',
});
}
});
}
});
setEvaluators(allEvaluators);
}, [formData.suppliersWithEvaluators]);
// 为评价人员初始化指标分配数据 - 作为单独的效果处理
useEffect(() => {
// 检查是否有新的评价人员需要初始化
2025-06-26 12:06:47 +08:00
const newAssignments = { ...indicatorAssignments.current };
2025-06-24 18:58:43 +08:00
let hasNewAssignments = false;
2025-06-26 12:06:47 +08:00
evaluators.forEach((evaluator) => {
if (!indicatorAssignments.current[evaluator.id]) {
2025-06-24 18:58:43 +08:00
newAssignments[evaluator.id] = {
type: EvaluateType.ALL,
indicatorIds: [],
};
hasNewAssignments = true;
}
});
if (hasNewAssignments) {
2025-06-26 12:06:47 +08:00
indicatorAssignments.current = newAssignments;
2025-06-24 18:58:43 +08:00
}
}, [evaluators, indicatorAssignments]);
// 同步数据回表单 - 使用防抖确保不会频繁触发
2025-06-26 12:06:47 +08:00
const previousValueRef = React.useRef<string>('');
2025-06-24 18:58:43 +08:00
useEffect(() => {
2025-06-26 12:06:47 +08:00
// 若当前还未初始化完成(没有任何指标数据),不应向父组件同步
if (evaluators.length === 0 || Object.keys(indicatorAssignments.current).length === 0) {
return;
}
2025-06-24 18:58:43 +08:00
// 将评价人员列表和指标分配数据同步回表单
2025-06-26 12:06:47 +08:00
const indicatorList = evaluators.map((evaluator) => ({
2025-06-24 18:58:43 +08:00
userId: evaluator.id,
userName: evaluator.name,
2025-06-26 12:06:47 +08:00
type: indicatorAssignments.current[evaluator.id]?.type ?? EvaluateType.ALL,
indicatorIds: indicatorAssignments.current[evaluator.id]?.indicatorIds ?? [],
2025-06-24 18:58:43 +08:00
}));
// 使用JSON字符串比较确保只有在真正变化时才更新
const currentValue = JSON.stringify(indicatorList);
if (currentValue !== previousValueRef.current) {
previousValueRef.current = currentValue;
onFormDataChange?.({
...formData,
indicatorList,
});
}
2025-06-26 12:06:47 +08:00
}, [evaluators, formData, onFormDataChange]);
2025-06-24 18:58:43 +08:00
// 暴露给父组件的方法
useImperativeHandle(ref, () => ({
validate: () => {
if (evaluators.length === 0) {
return {
valid: false,
message: '请先分配评价人员',
};
}
return { valid: true };
},
}));
2025-06-26 12:06:47 +08:00
// 获取当前评价人员名称
const getCurrentEvaluatorName = () => {
const evaluator = evaluators.find((e) => e.id === currentUserId);
return evaluator ? evaluator.name : currentUserId;
};
2025-06-24 18:58:43 +08:00
// 表格列定义
const columns: ColumnsType<PersonnelItem> = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '所属部门',
2025-06-26 12:06:47 +08:00
dataIndex: 'userDept',
key: 'userDept',
2025-06-24 18:58:43 +08:00
},
{
title: '员工编号',
2025-06-26 12:06:47 +08:00
dataIndex: 'id',
key: 'id',
2025-06-24 18:58:43 +08:00
},
{
title: '是否设置分工',
key: 'hasDivision',
render: (_: any, record: PersonnelItem) => {
2025-06-26 12:06:47 +08:00
const assignment = indicatorAssignments.current[record.id];
if (!assignment || assignment.indicatorIds.length === 0)
return <Tag color="red"></Tag>;
2025-06-24 18:58:43 +08:00
return <Tag color="green"></Tag>;
},
},
{
title: '操作',
key: 'action',
render: (_: any, record: PersonnelItem) => (
<Space size="middle">
2025-06-26 12:06:47 +08:00
<Button type="link" onClick={() => handleAssignIndicators(record.id)}>
</Button>
<Button type="link" onClick={() => handleViewAssignment(record.id)}>
</Button>
<Button type="link" onClick={() => handleRemoveEvaluator(record.id)}>
</Button>
2025-06-24 18:58:43 +08:00
</Space>
),
},
];
return (
<div>
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
onClick={handleOpenDivisionModal}
disabled={selectedRowKeys.length === 0}
>
</Button>
</div>
<Table
rowKey="id"
rowSelection={{
selectedRowKeys,
onChange: handleSelectChange,
}}
columns={columns}
dataSource={evaluators}
pagination={false}
/>
2025-06-24 20:32:55 +08:00
{/* 批量选择指标模板弹窗 */}
2025-06-24 18:58:43 +08:00
<Modal
2025-06-24 20:32:55 +08:00
title={`批量设置评价指标分工 (已选择 ${selectedRowKeys.length} 名评价人员)`}
visible={batchTemplateModalVisible}
onCancel={handleCloseBatchTemplateModal}
2025-06-26 12:06:47 +08:00
width={1200}
2025-06-24 20:32:55 +08:00
footer={[
<Button key="cancel" onClick={handleCloseBatchTemplateModal}>
</Button>,
<Button key="save" type="primary" onClick={handleBatchSetDivision}>
2025-06-26 12:06:47 +08:00
</Button>,
2025-06-24 20:32:55 +08:00
]}
2025-06-24 18:58:43 +08:00
>
2025-06-24 20:32:55 +08:00
<Spin spinning={loading}>
{templateData.length > 0 ? (
<EvaluateTemplateTable
value={templateData}
isDetail={true}
isCheck={true}
onSelect={handleBatchTemplateItemsSelect}
/>
) : (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
{loading ? '加载中...' : '暂无模板数据'}
</div>
)}
</Spin>
</Modal>
{/* 评价指标模板查看弹窗 */}
<Modal
title="设置评价指标分工"
visible={templateViewModalVisible}
onCancel={handleCloseTemplateViewModal}
width={1200}
2025-06-24 20:32:55 +08:00
footer={[
<Button key="cancel" onClick={handleCloseTemplateViewModal}>
</Button>,
<Button key="save" type="primary" onClick={handleSaveIndicatorAssignment}>
2025-06-26 12:06:47 +08:00
</Button>,
2025-06-24 20:32:55 +08:00
]}
>
<Spin spinning={loading}>
{templateData.length > 0 ? (
<EvaluateTemplateTable
value={templateData}
isDetail={true}
isCheck={true}
key={currentUserId}
onSelect={handleTemplateItemsSelect}
defaultSelectedIds={getCurrentUserSelectedIds()}
/>
) : (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
{loading ? '加载中...' : '暂无模板数据'}
</div>
)}
</Spin>
2025-06-24 18:58:43 +08:00
</Modal>
2025-06-26 12:06:47 +08:00
{/* 查看评价人员指标分工弹窗 */}
<Modal
title={`评价人员 ${getCurrentEvaluatorName()} 的指标分工`}
visible={viewModalVisible}
onCancel={handleCloseViewModal}
width={1200}
footer={[
<Button key="close" onClick={handleCloseViewModal}>
</Button>,
]}
>
<Spin spinning={loading}>
{filteredIndicators.length > 0 ? (
<EvaluateTemplateTable value={filteredIndicators} isDetail={true} />
) : (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
{loading ? '加载中...' : '暂无指标分工数据'}
</div>
)}
</Spin>
</Modal>
2025-06-24 18:58:43 +08:00
</div>
);
});
export default DivisionStep;