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

542 lines
18 KiB
TypeScript
Raw Normal View History

2025-06-26 12:06:47 +08:00
import React, {
useState,
useEffect,
forwardRef,
useImperativeHandle,
useCallback,
useRef,
} from 'react';
import { Table, Tag, Space, Button, message, Modal, Spin } from 'antd';
2025-06-24 18:58:43 +08:00
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';
import type { Dispatch } from 'umi';
2025-07-03 10:21:55 +08:00
import { connect, useIntl } from 'umi';
import type { SupplierTaskModelState } from '@/models/supplierTaskManage';
2025-06-24 18:58:43 +08:00
// 组件接收的Props定义
interface DivisionStepProps {
supplierTaskManage: SupplierTaskModelState;
dispatch: Dispatch;
innerRef?: any; // 使用 innerRef 作为属性名
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
}
// 定义组件,使用 innerRef 代替直接的 ref
const DivisionStepComponent = (props: DivisionStepProps) => {
2025-07-03 10:21:55 +08:00
const intl = useIntl();
const { supplierTaskManage, dispatch, innerRef } = props;
// 从 model 获取表单数据,避免通过 props 层层传递
const { taskFormData, mode } = supplierTaskManage;
2025-06-24 18:58:43 +08:00
// 从上一步获取的评价人员列表
2025-07-02 12:02:52 +08:00
const [evaluators, setEvaluators] = useState<SupplierTaskManage.PersonnelItem[]>([]);
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派生
2025-07-02 12:02:52 +08:00
const [indicators, setIndicators] = useState<SupplierTaskManage.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
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 getCurrentUserSelectedIds = useCallback(() => {
if (!currentUserId) return [];
// 直接从 taskFormData.userList 中获取当前用户的指标ID
const currentUser = taskFormData.userList?.find((user: any) => user.id === currentUserId);
return currentUser?.indicatorIds || [];
}, [currentUserId, taskFormData.userList]);
2025-06-26 12:06:47 +08:00
// 根据指标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 {
2025-07-03 10:21:55 +08:00
message.error(res.message || intl.formatMessage({ id: 'supplierTaskManage.message.fetchTemplatesFailed' }));
2025-06-24 20:32:55 +08:00
}
} catch (error) {
2025-07-03 10:21:55 +08:00
console.error(intl.formatMessage({ id: 'supplierTaskManage.message.fetchTemplatesFailed' }), error);
message.error(intl.formatMessage({ id: 'supplierTaskManage.message.fetchTemplatesFailed' }));
2025-06-24 20:32:55 +08:00
} finally {
setLoading(false);
}
};
/**
*
* Dva model
* @param updatedData
*/
const updateFormData = (updatedData: any) => {
// 通过dispatch更新model中的数据
dispatch({
type: 'supplierTaskManage/updateFormData', // action类型
payload: {
...updatedData,
},
});
};
2025-06-24 20:32:55 +08:00
// 监听templateId变化获取模板详情
useEffect(() => {
fetchTemplateDetail(taskFormData.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) {
2025-07-03 10:21:55 +08:00
message.warning(intl.formatMessage({ id: 'supplierTaskManage.message.noSelectedEvaluators' }));
2025-06-24 18:58:43 +08:00
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
};
// 处理指标选择 提取二级指标id
const getIndicatorNdListIds = (selectedItems: any[]) => {
const indicatorNdList = selectedItems.map((item) => item.indicatorNdList);
const indicatorNdListIds = indicatorNdList.flatMap((item) =>
item.map((ndItem: any) => ndItem.id),
2025-06-24 18:58:43 +08:00
);
return indicatorNdListIds;
};
// 处理指标,将处理后的指标放到dva中,同步处理userList,展示table 第二个参数是判断是否是批量设置,
// 如果批量则取 selectedRowKeys(table选中所有user)
const handleIndicatorAssignment = (indicatorNdListIds: string[], userIds: string[]) => {
// 读取dva中的数据只克隆一次
const indicatorList = JSON.parse(JSON.stringify(taskFormData?.indicatorList || []));
const userList = JSON.parse(JSON.stringify(taskFormData?.userList || []));
// 批量更新indicatorList和userList
userIds.forEach((userId) => {
// 更新indicatorList
2025-07-02 12:02:52 +08:00
indicatorList.forEach((item: SupplierTaskManage.IndicatorItem) => {
if (item.userId === userId) {
item.indicatorIds = [...new Set([...(item.indicatorIds || []), ...indicatorNdListIds])];
}
});
// 更新userList
2025-07-02 12:02:52 +08:00
userList.forEach((item: SupplierTaskManage.PersonnelItem) => {
if (item.id === userId) {
item.indicatorIds = indicatorNdListIds;
}
});
2025-06-24 18:58:43 +08:00
});
// 只调用一次updateFormData
updateFormData({
indicatorList,
userList,
});
};
// 保存指标分配
const handleSaveIndicatorAssignment = () => {
if (!currentUserId) {
2025-07-03 10:21:55 +08:00
message.warning(intl.formatMessage({ id: 'supplierTaskManage.message.noSelectedEvaluators' }));
return;
}
// 将选择回来的指标提取二级指标id
const indicatorNdListIds = getIndicatorNdListIds(selectedTemplateItems);
handleIndicatorAssignment(indicatorNdListIds, [currentUserId]);
setTemplateViewModalVisible(false);
2025-07-03 10:21:55 +08:00
message.success(intl.formatMessage({ id: 'supplierTaskManage.message.evaluatorDivisionSet' }));
};
// 批量设置指标分工
const handleBatchSetDivision = () => {
// 将选择回来的指标提取二级指标id
const indicatorNdListIds = getIndicatorNdListIds(batchSelectedTemplateItems);
const userIds = selectedRowKeys.map((key) => key.toString());
handleIndicatorAssignment(indicatorNdListIds, userIds);
2025-06-24 20:32:55 +08:00
setBatchTemplateModalVisible(false);
2025-07-03 10:21:55 +08:00
message.success(intl.formatMessage(
{ id: 'supplierTaskManage.message.batchDivisionSet' },
{ count: selectedRowKeys.length }
));
2025-06-24 18:58:43 +08:00
};
// 处理单个评价人员的指标分工
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[]) => {
setSelectedTemplateItems(selectedItems);
};
2025-06-24 18:58:43 +08:00
// 查看评价人员的指标分工
2025-07-02 12:02:52 +08:00
const handleViewAssignment = (person: SupplierTaskManage.PersonnelItem) => {
const assignment = person.indicatorIds;
2025-06-24 18:58:43 +08:00
if (!assignment) {
2025-07-03 10:21:55 +08:00
message.info(intl.formatMessage({ id: 'supplierTaskManage.message.noEvaluatorDivision' }));
2025-06-24 18:58:43 +08:00
return;
}
setCurrentUserId(person.id);
2025-06-26 12:06:47 +08:00
setLoading(true);
2025-06-24 18:58:43 +08:00
2025-06-26 12:06:47 +08:00
// 获取该评价人员的指标ID
const indicatorIds = person.indicatorIds;
2025-06-26 12:06:47 +08:00
// 过滤模板数据
const filtered = filterTemplateDataByIds(templateData, indicatorIds || []);
2025-06-26 12:06:47 +08:00
setFilteredIndicators(filtered);
setLoading(false);
setViewModalVisible(true);
};
// 关闭查看模态框
const handleCloseViewModal = () => {
setViewModalVisible(false);
2025-06-24 18:58:43 +08:00
};
// 删除评价人员
const handleRemoveEvaluator = (userId: string) => {
Modal.confirm({
2025-07-03 10:21:55 +08:00
title: intl.formatMessage({ id: 'supplierTaskManage.modal.delete.title' }),
content: intl.formatMessage({ id: 'supplierTaskManage.modal.delete.content' }),
okText: intl.formatMessage({ id: 'supplierTaskManage.button.confirm' }),
cancelText: intl.formatMessage({ id: 'supplierTaskManage.button.cancel' }),
2025-06-24 18:58:43 +08:00
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
//更新dva中的userList
dispatch({
type: 'supplierTaskManage/deleteUser',
payload: {
userIds: [userId],
},
});
2025-06-24 18:58:43 +08:00
2025-07-03 10:21:55 +08:00
message.success(intl.formatMessage({ id: 'supplierTaskManage.message.deleteSuccess' }));
2025-06-24 18:58:43 +08:00
},
});
};
// 从上一步获取评价人员列表 - 避免频繁更新
useEffect(() => {
if (!taskFormData.userList) return;
2025-07-02 12:02:52 +08:00
setEvaluators(taskFormData.userList as SupplierTaskManage.PersonnelItem[]);
}, [taskFormData.userList]);
2025-06-24 18:58:43 +08:00
// 暴露给父组件的方法
useImperativeHandle(innerRef, () => ({
2025-06-24 18:58:43 +08:00
validate: () => {
if (evaluators.length === 0) {
return {
valid: false,
2025-07-03 10:21:55 +08:00
message: intl.formatMessage({ id: 'supplierTaskManage.message.noEvaluatorAssigned' }),
2025-06-24 18:58:43 +08:00
};
}
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
// 表格列定义
2025-07-02 12:02:52 +08:00
const columns: ColumnsType<SupplierTaskManage.PersonnelItem> = [
2025-06-24 18:58:43 +08:00
{
2025-07-03 10:21:55 +08:00
title: intl.formatMessage({ id: 'supplierTaskManage.column.name' }),
2025-06-24 18:58:43 +08:00
dataIndex: 'name',
key: 'name',
},
{
2025-07-03 10:21:55 +08:00
title: intl.formatMessage({ id: 'supplierTaskManage.column.userDept' }),
2025-06-26 12:06:47 +08:00
dataIndex: 'userDept',
key: 'userDept',
2025-06-24 18:58:43 +08:00
},
{
2025-07-03 10:21:55 +08:00
title: intl.formatMessage({ id: 'supplierTaskManage.column.id' }),
2025-06-26 12:06:47 +08:00
dataIndex: 'id',
key: 'id',
2025-06-24 18:58:43 +08:00
},
{
2025-07-03 10:21:55 +08:00
title: intl.formatMessage({ id: 'supplierTaskManage.column.hasDivision' }),
2025-06-24 18:58:43 +08:00
key: 'hasDivision',
2025-07-02 12:02:52 +08:00
render: (_: any, record: SupplierTaskManage.PersonnelItem) => {
if (!record.indicatorIds || record.indicatorIds.length === 0)
2025-07-03 10:21:55 +08:00
return <Tag color="red">{intl.formatMessage({ id: 'supplierTaskManage.status.notSet' })}</Tag>;
return <Tag color="green">{intl.formatMessage({ id: 'supplierTaskManage.status.set' })}</Tag>;
2025-06-24 18:58:43 +08:00
},
},
{
2025-07-03 10:21:55 +08:00
title: intl.formatMessage({ id: 'supplierTaskManage.column.action' }),
2025-06-24 18:58:43 +08:00
key: 'action',
2025-07-02 12:02:52 +08:00
render: (_: any, record: SupplierTaskManage.PersonnelItem) => (
2025-06-24 18:58:43 +08:00
<Space size="middle">
{mode !== 'division' && (
<>
<Button type="link" onClick={() => handleAssignIndicators(record.id)}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.evaluatorDivision' })}
</Button>
<Button type="link" onClick={() => handleRemoveEvaluator(record.id)}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.delete' })}
</Button>
</>
)}
<Button type="link" onClick={() => handleViewAssignment(record)}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.view' })}
2025-06-26 12:06:47 +08:00
</Button>
2025-06-24 18:58:43 +08:00
</Space>
),
},
];
const rowSelection = {
selectedRowKeys,
onChange: handleSelectChange,
};
2025-06-24 18:58:43 +08:00
return (
<div>
{mode !== 'division' && (
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
onClick={handleOpenDivisionModal}
disabled={selectedRowKeys.length === 0}
>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.setEvaluationDivision' })}
</Button>
</div>
)}
2025-06-24 18:58:43 +08:00
<Table
rowKey="id"
rowSelection={mode === 'division' ? undefined : rowSelection}
2025-06-24 18:58:43 +08:00
columns={columns}
dataSource={evaluators}
pagination={false}
/>
2025-06-24 20:32:55 +08:00
{/* 批量选择指标模板弹窗 */}
2025-06-24 18:58:43 +08:00
<Modal
2025-07-03 10:21:55 +08:00
title={intl.formatMessage(
{ id: 'supplierTaskManage.modal.batchDivision.title' },
{ count: selectedRowKeys.length }
)}
2025-06-24 20:32:55 +08:00
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}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.cancel' })}
2025-06-24 20:32:55 +08:00
</Button>,
<Button key="save" type="primary" onClick={handleBatchSetDivision}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.saveAndConfirm' })}
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' }}>
2025-07-03 10:21:55 +08:00
{loading ? intl.formatMessage({ id: 'supplierTaskManage.text.loading' }) : intl.formatMessage({ id: 'supplierTaskManage.text.noTemplateData' })}
2025-06-24 20:32:55 +08:00
</div>
)}
</Spin>
</Modal>
{/* 设置评价指标分工 */}
2025-06-24 20:32:55 +08:00
<Modal
2025-07-03 10:21:55 +08:00
title={intl.formatMessage({ id: 'supplierTaskManage.modal.division.title' })}
2025-06-24 20:32:55 +08:00
visible={templateViewModalVisible}
onCancel={handleCloseTemplateViewModal}
width={1200}
2025-06-24 20:32:55 +08:00
footer={[
<Button key="cancel" onClick={handleCloseTemplateViewModal}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.cancel' })}
2025-06-24 20:32:55 +08:00
</Button>,
<Button key="save" type="primary" onClick={handleSaveIndicatorAssignment}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.save' })}
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' }}>
2025-07-03 10:21:55 +08:00
{loading ? intl.formatMessage({ id: 'supplierTaskManage.text.loading' }) : intl.formatMessage({ id: 'supplierTaskManage.text.noTemplateData' })}
2025-06-24 20:32:55 +08:00
</div>
)}
</Spin>
2025-06-24 18:58:43 +08:00
</Modal>
2025-06-26 12:06:47 +08:00
{/* 查看评价人员指标分工弹窗 */}
<Modal
2025-07-03 10:21:55 +08:00
title={intl.formatMessage(
{ id: 'supplierTaskManage.modal.viewDivision.title' },
{ name: getCurrentEvaluatorName() }
)}
2025-06-26 12:06:47 +08:00
visible={viewModalVisible}
onCancel={handleCloseViewModal}
width={1200}
footer={[
<Button key="close" onClick={handleCloseViewModal}>
2025-07-03 10:21:55 +08:00
{intl.formatMessage({ id: 'supplierTaskManage.button.close' })}
2025-06-26 12:06:47 +08:00
</Button>,
]}
>
<Spin spinning={loading}>
{filteredIndicators.length > 0 ? (
<EvaluateTemplateTable value={filteredIndicators} isDetail={true} />
) : (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
2025-07-03 10:21:55 +08:00
{loading ? intl.formatMessage({ id: 'supplierTaskManage.text.loading' }) : intl.formatMessage({ id: 'supplierTaskManage.text.noDivisionData' })}
2025-06-26 12:06:47 +08:00
</div>
)}
</Spin>
</Modal>
2025-06-24 18:58:43 +08:00
</div>
);
};
/**
* Dva model
*/
const ConnectedComponent = connect(
({ supplierTaskManage }: { supplierTaskManage: SupplierTaskModelState }) => ({
supplierTaskManage,
}),
)(DivisionStepComponent);
/**
* ref innerRef
*/
const DivisionStep = forwardRef((props: any, ref) => (
<ConnectedComponent {...props} innerRef={ref} />
));
2025-06-24 18:58:43 +08:00
export default DivisionStep;