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

542 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, {
useState,
useEffect,
forwardRef,
useImperativeHandle,
useCallback,
useRef,
} from 'react';
import { Table, Tag, Space, Button, message, Modal, Spin } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable';
import { getTemplateDetail } from '@/servers/api/supplierEvaluate';
import type { Dispatch } from 'umi';
import { connect, useIntl } from 'umi';
import type { SupplierTaskModelState } from '@/models/supplierTaskManage';
// 组件接收的Props定义
interface DivisionStepProps {
supplierTaskManage: SupplierTaskModelState;
dispatch: Dispatch;
innerRef?: any; // 使用 innerRef 作为属性名
}
// 评价方式枚举
// 注意type值是根据用户是否关联了指标自动计算的不是由用户直接选择的
// 默认为0(按评价单)当用户关联了指标则为1(按指标)
enum EvaluateType {
ALL = 0, // 按评价单评价(全部指标)
INDICATOR = 1, // 按指标评价(部分指标)
}
// 定义组件,使用 innerRef 代替直接的 ref
const DivisionStepComponent = (props: DivisionStepProps) => {
const intl = useIntl();
const { supplierTaskManage, dispatch, innerRef } = props;
// 从 model 获取表单数据,避免通过 props 层层传递
const { taskFormData, mode } = supplierTaskManage;
// 从上一步获取的评价人员列表
const [evaluators, setEvaluators] = useState<SupplierTaskManage.PersonnelItem[]>([]);
// 选中的行keys
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
// 指标列表 - 不再直接使用mockIndicators而是从templateData派生
const [indicators, setIndicators] = useState<SupplierTaskManage.IndicatorItem[]>([]);
// 评价指标模板查看弹窗可见性
const [templateViewModalVisible, setTemplateViewModalVisible] = useState(false);
// 批量指标设置弹窗可见性
const [batchTemplateModalVisible, setBatchTemplateModalVisible] = useState(false);
// 批量选择的模板项
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[]>([]);
// 查看指标分工弹窗可见性
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]);
// 根据指标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;
}, []);
// 获取模板详情 先写死 "1937123786334322688" 省的一步一步操作
const fetchTemplateDetail = async (templateId: string) => {
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 || intl.formatMessage({ id: 'supplierTaskManage.message.fetchTemplatesFailed' }));
}
} catch (error) {
console.error(intl.formatMessage({ id: 'supplierTaskManage.message.fetchTemplatesFailed' }), error);
message.error(intl.formatMessage({ id: 'supplierTaskManage.message.fetchTemplatesFailed' }));
} finally {
setLoading(false);
}
};
/**
* 更新表单数据
* 将本地状态同步到 Dva model
* @param updatedData 要更新的部分数据
*/
const updateFormData = (updatedData: any) => {
// 通过dispatch更新model中的数据
dispatch({
type: 'supplierTaskManage/updateFormData', // action类型
payload: {
...updatedData,
},
});
};
// 监听templateId变化获取模板详情
useEffect(() => {
fetchTemplateDetail(taskFormData.templateId as string);
}, []);
// 处理行选择变化
const handleSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
// 打开指标分工弹窗
const handleOpenDivisionModal = () => {
if (selectedRowKeys.length === 0) {
message.warning(intl.formatMessage({ id: 'supplierTaskManage.message.noSelectedEvaluators' }));
return;
}
// 直接显示批量模板选择弹窗
setBatchTemplateModalVisible(true);
// 重置已选中的模板项
setBatchSelectedTemplateItems([]);
};
// 处理批量模板指标选择
const handleBatchTemplateItemsSelect = (selectedItems: any[]) => {
setBatchSelectedTemplateItems(selectedItems);
};
// 关闭批量模板选择弹窗
const handleCloseBatchTemplateModal = () => {
setBatchTemplateModalVisible(false);
};
// 处理指标选择 提取二级指标id
const getIndicatorNdListIds = (selectedItems: any[]) => {
const indicatorNdList = selectedItems.map((item) => item.indicatorNdList);
const indicatorNdListIds = indicatorNdList.flatMap((item) =>
item.map((ndItem: any) => ndItem.id),
);
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
indicatorList.forEach((item: SupplierTaskManage.IndicatorItem) => {
if (item.userId === userId) {
item.indicatorIds = [...new Set([...(item.indicatorIds || []), ...indicatorNdListIds])];
}
});
// 更新userList
userList.forEach((item: SupplierTaskManage.PersonnelItem) => {
if (item.id === userId) {
item.indicatorIds = indicatorNdListIds;
}
});
});
// 只调用一次updateFormData
updateFormData({
indicatorList,
userList,
});
};
// 保存指标分配
const handleSaveIndicatorAssignment = () => {
if (!currentUserId) {
message.warning(intl.formatMessage({ id: 'supplierTaskManage.message.noSelectedEvaluators' }));
return;
}
// 将选择回来的指标提取二级指标id
const indicatorNdListIds = getIndicatorNdListIds(selectedTemplateItems);
handleIndicatorAssignment(indicatorNdListIds, [currentUserId]);
setTemplateViewModalVisible(false);
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);
setBatchTemplateModalVisible(false);
message.success(intl.formatMessage(
{ id: 'supplierTaskManage.message.batchDivisionSet' },
{ count: selectedRowKeys.length }
));
};
// 处理单个评价人员的指标分工
const handleAssignIndicators = (userId: string) => {
setCurrentUserId(userId);
// 重置已选中的指标项
setSelectedTemplateItems([]);
// 打开模态框
setTemplateViewModalVisible(true);
};
// 关闭模板查看模态框
const handleCloseTemplateViewModal = () => {
setTemplateViewModalVisible(false);
};
// 处理模板指标选择
const handleTemplateItemsSelect = (selectedItems: any[]) => {
setSelectedTemplateItems(selectedItems);
};
// 查看评价人员的指标分工
const handleViewAssignment = (person: SupplierTaskManage.PersonnelItem) => {
const assignment = person.indicatorIds;
if (!assignment) {
message.info(intl.formatMessage({ id: 'supplierTaskManage.message.noEvaluatorDivision' }));
return;
}
setCurrentUserId(person.id);
setLoading(true);
// 获取该评价人员的指标ID
const indicatorIds = person.indicatorIds;
// 过滤模板数据
const filtered = filterTemplateDataByIds(templateData, indicatorIds || []);
setFilteredIndicators(filtered);
setLoading(false);
setViewModalVisible(true);
};
// 关闭查看模态框
const handleCloseViewModal = () => {
setViewModalVisible(false);
};
// 删除评价人员
const handleRemoveEvaluator = (userId: string) => {
Modal.confirm({
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' }),
onOk: () => {
// 更新评价人员列表
setEvaluators((prev) => prev.filter((e) => e.id !== userId));
//更新dva中的userList
dispatch({
type: 'supplierTaskManage/deleteUser',
payload: {
userIds: [userId],
},
});
message.success(intl.formatMessage({ id: 'supplierTaskManage.message.deleteSuccess' }));
},
});
};
// 从上一步获取评价人员列表 - 避免频繁更新
useEffect(() => {
if (!taskFormData.userList) return;
setEvaluators(taskFormData.userList as SupplierTaskManage.PersonnelItem[]);
}, [taskFormData.userList]);
// 暴露给父组件的方法
useImperativeHandle(innerRef, () => ({
validate: () => {
if (evaluators.length === 0) {
return {
valid: false,
message: intl.formatMessage({ id: 'supplierTaskManage.message.noEvaluatorAssigned' }),
};
}
return { valid: true };
},
}));
// 选择完
// 获取当前评价人员名称
const getCurrentEvaluatorName = () => {
const evaluator = evaluators.find((e) => e.id === currentUserId);
return evaluator ? evaluator.name : currentUserId;
};
// 表格列定义
const columns: ColumnsType<SupplierTaskManage.PersonnelItem> = [
{
title: intl.formatMessage({ id: 'supplierTaskManage.column.name' }),
dataIndex: 'name',
key: 'name',
},
{
title: intl.formatMessage({ id: 'supplierTaskManage.column.userDept' }),
dataIndex: 'userDept',
key: 'userDept',
},
{
title: intl.formatMessage({ id: 'supplierTaskManage.column.id' }),
dataIndex: 'id',
key: 'id',
},
{
title: intl.formatMessage({ id: 'supplierTaskManage.column.hasDivision' }),
key: 'hasDivision',
render: (_: any, record: SupplierTaskManage.PersonnelItem) => {
if (!record.indicatorIds || record.indicatorIds.length === 0)
return <Tag color="red">{intl.formatMessage({ id: 'supplierTaskManage.status.notSet' })}</Tag>;
return <Tag color="green">{intl.formatMessage({ id: 'supplierTaskManage.status.set' })}</Tag>;
},
},
{
title: intl.formatMessage({ id: 'supplierTaskManage.column.action' }),
key: 'action',
render: (_: any, record: SupplierTaskManage.PersonnelItem) => (
<Space size="middle">
{mode !== 'division' && (
<>
<Button type="link" onClick={() => handleAssignIndicators(record.id)}>
{intl.formatMessage({ id: 'supplierTaskManage.button.evaluatorDivision' })}
</Button>
<Button type="link" onClick={() => handleRemoveEvaluator(record.id)}>
{intl.formatMessage({ id: 'supplierTaskManage.button.delete' })}
</Button>
</>
)}
<Button type="link" onClick={() => handleViewAssignment(record)}>
{intl.formatMessage({ id: 'supplierTaskManage.button.view' })}
</Button>
</Space>
),
},
];
const rowSelection = {
selectedRowKeys,
onChange: handleSelectChange,
};
return (
<div>
{mode !== 'division' && (
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
onClick={handleOpenDivisionModal}
disabled={selectedRowKeys.length === 0}
>
{intl.formatMessage({ id: 'supplierTaskManage.button.setEvaluationDivision' })}
</Button>
</div>
)}
<Table
rowKey="id"
rowSelection={mode === 'division' ? undefined : rowSelection}
columns={columns}
dataSource={evaluators}
pagination={false}
/>
{/* 批量选择指标模板弹窗 */}
<Modal
title={intl.formatMessage(
{ id: 'supplierTaskManage.modal.batchDivision.title' },
{ count: selectedRowKeys.length }
)}
visible={batchTemplateModalVisible}
onCancel={handleCloseBatchTemplateModal}
width={1200}
footer={[
<Button key="cancel" onClick={handleCloseBatchTemplateModal}>
{intl.formatMessage({ id: 'supplierTaskManage.button.cancel' })}
</Button>,
<Button key="save" type="primary" onClick={handleBatchSetDivision}>
{intl.formatMessage({ id: 'supplierTaskManage.button.saveAndConfirm' })}
</Button>,
]}
>
<Spin spinning={loading}>
{templateData.length > 0 ? (
<EvaluateTemplateTable
value={templateData}
isDetail={true}
isCheck={true}
onSelect={handleBatchTemplateItemsSelect}
/>
) : (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
{loading ? intl.formatMessage({ id: 'supplierTaskManage.text.loading' }) : intl.formatMessage({ id: 'supplierTaskManage.text.noTemplateData' })}
</div>
)}
</Spin>
</Modal>
{/* 设置评价指标分工 */}
<Modal
title={intl.formatMessage({ id: 'supplierTaskManage.modal.division.title' })}
visible={templateViewModalVisible}
onCancel={handleCloseTemplateViewModal}
width={1200}
footer={[
<Button key="cancel" onClick={handleCloseTemplateViewModal}>
{intl.formatMessage({ id: 'supplierTaskManage.button.cancel' })}
</Button>,
<Button key="save" type="primary" onClick={handleSaveIndicatorAssignment}>
{intl.formatMessage({ id: 'supplierTaskManage.button.save' })}
</Button>,
]}
>
<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 ? intl.formatMessage({ id: 'supplierTaskManage.text.loading' }) : intl.formatMessage({ id: 'supplierTaskManage.text.noTemplateData' })}
</div>
)}
</Spin>
</Modal>
{/* 查看评价人员指标分工弹窗 */}
<Modal
title={intl.formatMessage(
{ id: 'supplierTaskManage.modal.viewDivision.title' },
{ name: getCurrentEvaluatorName() }
)}
visible={viewModalVisible}
onCancel={handleCloseViewModal}
width={1200}
footer={[
<Button key="close" onClick={handleCloseViewModal}>
{intl.formatMessage({ id: 'supplierTaskManage.button.close' })}
</Button>,
]}
>
<Spin spinning={loading}>
{filteredIndicators.length > 0 ? (
<EvaluateTemplateTable value={filteredIndicators} isDetail={true} />
) : (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
{loading ? intl.formatMessage({ id: 'supplierTaskManage.text.loading' }) : intl.formatMessage({ id: 'supplierTaskManage.text.noDivisionData' })}
</div>
)}
</Spin>
</Modal>
</div>
);
};
/**
* 连接 Dva model
*/
const ConnectedComponent = connect(
({ supplierTaskManage }: { supplierTaskManage: SupplierTaskModelState }) => ({
supplierTaskManage,
}),
)(DivisionStepComponent);
/**
* 外层转发 ref 到 innerRef
*/
const DivisionStep = forwardRef((props: any, ref) => (
<ConnectedComponent {...props} innerRef={ref} />
));
export default DivisionStep;