542 lines
18 KiB
TypeScript
542 lines
18 KiB
TypeScript
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;
|