暂存评价任务新增

This commit is contained in:
linxd
2025-06-24 18:58:43 +08:00
parent 9a45e65db1
commit d7df286214
22 changed files with 1502 additions and 908 deletions

View File

@ -38,19 +38,9 @@ const BasicInfoStep = forwardRef<any, BasicInfoStepProps>(({ formData, onFormDat
const response = await getAllTemplates();
if (response.success && response.data) {
setTemplates(response.data);
} else {
setTemplates([
{ id: '1', templateName: '不限品类模板', categoryLimitation: '0' },
{ id: '2', templateName: '限制品类模板', categoryLimitation: '1' },
]);
}
} catch (error) {
console.error('获取模板列表失败:', error);
// 使用模拟数据
setTemplates([
{ id: '1', templateName: '不限品类模板', categoryLimitation: '0' },
{ id: '2', templateName: '限制品类模板', categoryLimitation: '1' },
]);
} finally {
setLoading(false);
}
@ -66,33 +56,22 @@ const BasicInfoStep = forwardRef<any, BasicInfoStepProps>(({ formData, onFormDat
}
}, []);
// 当formData变化时更新表单值
useEffect(() => {
if (formData) {
// 处理日期字段,确保正确设置
const formValues = {
...formData,
startTime: formData.startTime ? moment(formData.startTime) : undefined,
endTime: formData.endTime ? moment(formData.endTime) : undefined,
};
form.setFieldsValue(formValues);
}
}, [formData, form]);
// 表单值变化时触发
const handleValuesChange = (changedValues: any, allValues: any) => {
// 处理模板变更
if (changedValues.templateId) {
const template = templates.find((t) => t.id === changedValues.templateId);
if (template) {
// 更新品类限制类型
form.setFieldsValue({
categoryLimitation: template.categoryLimitation || '0',
});
// 如果选择了不限品类的模板,清空品类选择
if (template.categoryLimitation === '0') {
form.setFieldsValue({
categoryId: undefined,
});
}
}
}
// 默认设置weightStatus为0
const formattedValues = {
...allValues,
weightStatus: 0,
};
onFormDataChange(formattedValues);
onFormDataChange(allValues);
};
// 年度选项生成
@ -107,9 +86,9 @@ const BasicInfoStep = forwardRef<any, BasicInfoStepProps>(({ formData, onFormDat
// 判断是否显示品类选择器
const shouldShowCategorySelector = useCallback(() => {
const categoryLimitation = form.getFieldValue('categoryLimitation');
const categoryLimitation = formData.categoryLimitation;
return categoryLimitation === CategoryLimitationType.LIMITED;
}, [form]);
}, [formData]);
return (

View File

@ -0,0 +1,370 @@
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Card, Table, Tag, Switch, Space, Button, message, Modal, Radio, Checkbox, Row, Col } from 'antd';
import type { PersonnelItem } from '@/servers/types/evaluator';
import type { ColumnsType } from 'antd/es/table';
import type { CheckboxValueType } from 'antd/es/checkbox/Group';
import styles from '../supplierTaskManageAdd.less';
// 评价指标类型定义
interface IndicatorItem {
id: string;
name: string;
description: string;
}
// 组件接收的Props定义
interface DivisionStepProps {
formData: any;
onFormDataChange?: (values: any) => void;
}
// 评价方式枚举
enum EvaluateType {
ALL = 'ALL', // 按评价单评价(全部指标)
INDICATOR = 'INDICATOR', // 按指标评价(部分指标)
}
// 模拟的评价指标数据
const mockIndicators: IndicatorItem[] = [
{ id: 'I001', name: '产品质量', description: '评估供应商产品质量' },
{ id: 'I002', name: '交货及时性', description: '评估供应商交货的及时性' },
{ id: 'I003', name: '服务水平', description: '评估供应商提供的服务水平' },
{ id: 'I004', name: '价格竞争力', description: '评估供应商产品价格的竞争力' },
{ id: 'I005', name: '技术能力', description: '评估供应商的技术创新能力' },
];
const DivisionStep = forwardRef<any, DivisionStepProps>(({ formData, onFormDataChange }, ref) => {
// 从上一步获取的评价人员列表
const [evaluators, setEvaluators] = useState<PersonnelItem[]>([]);
// 评价人员指标分配数据
const [indicatorAssignments, setIndicatorAssignments] = useState<{
[userId: string]: {
type: EvaluateType;
indicatorIds: string[];
};
}>({});
// 选中的行keys
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
// 指标列表
const [indicators] = useState<IndicatorItem[]>(mockIndicators);
// 指标分工弹窗可见性
const [divisionModalVisible, setDivisionModalVisible] = useState(false);
// 评价方式类型
const [batchEvaluateType, setBatchEvaluateType] = useState<EvaluateType>(EvaluateType.ALL);
// 批量选择的指标
const [batchSelectedIndicators, setBatchSelectedIndicators] = useState<string[]>([]);
// 处理行选择变化
const handleSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
// 打开指标分工弹窗
const handleOpenDivisionModal = () => {
if (selectedRowKeys.length === 0) {
message.warning('请先选择评价人员');
return;
}
setDivisionModalVisible(true);
};
// 处理评价方式变更
const handleEvaluateTypeChange = (e: any) => {
setBatchEvaluateType(e.target.value);
};
// 处理指标选择变更
const handleIndicatorChange = (checkedValues: CheckboxValueType[]) => {
setBatchSelectedIndicators(checkedValues.map(v => v.toString()));
};
// 批量设置指标分工
const handleBatchSetDivision = () => {
// 获取选中的评价人员
const selectedEvaluators = evaluators.filter(
evaluator => selectedRowKeys.includes(evaluator.id)
);
// 更新指标分配数据
const newAssignments = { ...indicatorAssignments };
selectedEvaluators.forEach(evaluator => {
newAssignments[evaluator.id] = {
type: batchEvaluateType,
indicatorIds: batchEvaluateType === EvaluateType.INDICATOR ? batchSelectedIndicators : [],
};
});
setIndicatorAssignments(newAssignments);
setDivisionModalVisible(false);
message.success(`已为${selectedRowKeys.length}名评价人员设置分工`);
};
// 处理单个评价人员的指标分工
const handleAssignIndicators = (userId: string) => {
Modal.info({
title: '评价指标分工',
content: '此功能将在后续完善',
okText: '确定',
});
};
// 查看评价人员的指标分工
const handleViewAssignment = (userId: string) => {
const assignment = indicatorAssignments[userId];
if (!assignment) {
message.info('该评价人员尚未设置分工');
return;
}
const assignedIndicators = indicators.filter(ind =>
assignment.type === EvaluateType.ALL ||
assignment.indicatorIds.includes(ind.id)
);
Modal.info({
title: '查看评价指标分工',
content: (
<div>
<p>: {assignment.type === EvaluateType.ALL ? '按评价单评价' : '按指标评价'}</p>
<p>: </p>
<ul>
{assignedIndicators.map(ind => (
<li key={ind.id}>{ind.name}</li>
))}
</ul>
</div>
),
okText: '确定',
});
};
// 删除评价人员
const handleRemoveEvaluator = (userId: string) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除该评价人员吗?',
okText: '确定',
cancelText: '取消',
onOk: () => {
// 更新评价人员列表
setEvaluators(prev => prev.filter(e => e.id !== userId));
// 更新指标分配数据
const newAssignments = { ...indicatorAssignments };
delete newAssignments[userId];
setIndicatorAssignments(newAssignments);
message.success('已删除评价人员');
},
});
};
// 初始化从formData中提取指标分配数据
useEffect(() => {
if (formData.indicatorList) {
// 如果已有指标分配数据,直接使用
const assignments: any = {};
formData.indicatorList.forEach((item: any) => {
assignments[item.userId] = {
type: item.type,
indicatorIds: item.indicatorIds || [],
};
});
setIndicatorAssignments(assignments);
}
}, [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) => {
// 检查是否已存在(避免重复)
if (!allEvaluators.some(e => e.id === evaluator.id)) {
allEvaluators.push({
...evaluator,
// 添加单位和员工编号,假设这些字段可能不存在
company: evaluator.company || supplier.supplierName || '未知单位',
employeeNumber: evaluator.employeeNumber || `EMP${evaluator.id.slice(-4)}`,
department: evaluator.department || '未知部门',
});
}
});
}
});
setEvaluators(allEvaluators);
}, [formData.suppliersWithEvaluators]);
// 为评价人员初始化指标分配数据 - 作为单独的效果处理
useEffect(() => {
// 检查是否有新的评价人员需要初始化
const newAssignments = { ...indicatorAssignments };
let hasNewAssignments = false;
evaluators.forEach(evaluator => {
if (!indicatorAssignments[evaluator.id]) {
newAssignments[evaluator.id] = {
type: EvaluateType.ALL,
indicatorIds: [],
};
hasNewAssignments = true;
}
});
if (hasNewAssignments) {
setIndicatorAssignments(newAssignments);
}
}, [evaluators, indicatorAssignments]);
// 同步数据回表单 - 使用防抖确保不会频繁触发
const previousValueRef = React.useRef<string>("");
useEffect(() => {
// 将评价人员列表和指标分配数据同步回表单
const indicatorList = evaluators.map(evaluator => ({
userId: evaluator.id,
userName: evaluator.name,
type: indicatorAssignments[evaluator.id]?.type || EvaluateType.ALL,
indicatorIds: indicatorAssignments[evaluator.id]?.indicatorIds || [],
}));
// 使用JSON字符串比较确保只有在真正变化时才更新
const currentValue = JSON.stringify(indicatorList);
if (currentValue !== previousValueRef.current) {
previousValueRef.current = currentValue;
onFormDataChange?.({
...formData,
indicatorList,
});
}
}, [evaluators, indicatorAssignments, formData, onFormDataChange]);
// 暴露给父组件的方法
useImperativeHandle(ref, () => ({
validate: () => {
if (evaluators.length === 0) {
return {
valid: false,
message: '请先分配评价人员',
};
}
return { valid: true };
},
}));
// 表格列定义
const columns: ColumnsType<PersonnelItem> = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '所属单位',
dataIndex: 'company',
key: 'company',
},
{
title: '所属部门',
dataIndex: 'department',
key: 'department',
},
{
title: '员工编号',
dataIndex: 'employeeNumber',
key: 'employeeNumber',
},
{
title: '是否设置分工',
key: 'hasDivision',
render: (_: any, record: PersonnelItem) => {
const assignment = indicatorAssignments[record.id];
if (!assignment) return <Tag color="red"></Tag>;
return <Tag color="green"></Tag>;
},
},
{
title: '操作',
key: 'action',
render: (_: any, record: PersonnelItem) => (
<Space size="middle">
<Button type="link" onClick={() => handleAssignIndicators(record.id)}></Button>
<Button type="link" onClick={() => handleViewAssignment(record.id)}></Button>
<Button type="link" onClick={() => handleRemoveEvaluator(record.id)}></Button>
</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}
/>
{/* 批量设置指标分工弹窗 */}
<Modal
title="批量设置评价指标分工"
visible={divisionModalVisible}
onOk={handleBatchSetDivision}
onCancel={() => setDivisionModalVisible(false)}
okText="确定"
cancelText="取消"
width={700}
>
<div>
<p> {selectedRowKeys.length} </p>
<Radio.Group defaultValue={EvaluateType.ALL} onChange={handleEvaluateTypeChange}>
<Radio value={EvaluateType.ALL}></Radio>
<Radio value={EvaluateType.INDICATOR}></Radio>
</Radio.Group>
<div style={{ marginTop: 16 }}>
<p></p>
<Checkbox.Group style={{ width: '100%' }} onChange={handleIndicatorChange}>
<Row>
{indicators.map(indicator => (
<Col span={8} key={indicator.id}>
<Checkbox value={indicator.id}>{indicator.name}</Checkbox>
</Col>
))}
</Row>
</Checkbox.Group>
</div>
</div>
</Modal>
</div>
);
});
export default DivisionStep;

View File

@ -0,0 +1,36 @@
import React from 'react';
import { Modal } from 'antd';
import EvaluateTaskPersonnelSelector from '@/components/EvaluateTaskPersonnelSelector/EvaluateTaskPersonnelSelector';
import type { PersonnelItem } from '@/servers/types/evaluator';
interface BatchEvaluatorModalProps {
visible: boolean;
onCancel: () => void;
onSelect: (selectedEvaluators: PersonnelItem[]) => void;
selectedPersonnel?: PersonnelItem[];
}
const BatchEvaluatorModal: React.FC<BatchEvaluatorModalProps> = ({
visible,
onCancel,
onSelect,
selectedPersonnel = [],
}) => {
return (
<Modal
title="批量选择评价人员"
visible={visible}
onCancel={onCancel}
footer={null}
width={700}
destroyOnClose={false}
>
<EvaluateTaskPersonnelSelector
onSelect={onSelect}
selectedPersonnel={selectedPersonnel}
/>
</Modal>
);
};
export default BatchEvaluatorModal;

View File

@ -0,0 +1,107 @@
import React, { useEffect, useState } from 'react';
import { Modal, Button, List, message } from 'antd';
import EvaluateTaskPersonnelSelector from '@/components/EvaluateTaskPersonnelSelector/EvaluateTaskPersonnelSelector';
import { ModalMode } from '@/servers/types/evaluator';
import type { PersonnelItem, SupplierItem } from '@/servers/types/evaluator';
interface SupplierEvaluatorModalProps {
visible: boolean; // 控制弹窗显示/隐藏
onCancel: () => void; // 取消按钮回调函数
onSelect: (personnel: PersonnelItem[]) => void; // 选择人员后的回调函数
currentSupplier: SupplierItem | null; // 当前操作的供应商对象
mode: ModalMode; // 弹窗模式SELECT(选择) 或 VIEW(查看)
}
const SupplierEvaluatorModal: React.FC<SupplierEvaluatorModalProps> = ({
visible,
onCancel,
onSelect,
currentSupplier,
mode,
}) => {
// 本地保存当前选中的人员,确保在弹窗打开/关闭时能正确处理数据
const [localSelectedPersonnel, setLocalSelectedPersonnel] = useState<PersonnelItem[]>([]);
// 当currentSupplier变化时更新本地的选中人员
useEffect(() => {
if (currentSupplier && currentSupplier.evaluators) {
setLocalSelectedPersonnel(currentSupplier.evaluators);
} else {
setLocalSelectedPersonnel([]);
}
}, [currentSupplier]);
// 处理选择人员的回调
const handleSelect = (personnel: PersonnelItem[]) => {
if (personnel.length === 0) {
message.warning('请至少选择一名评价人员');
return;
}
setLocalSelectedPersonnel(personnel);
onSelect(personnel);
};
// 渲染评价人员列表(用于查看模式)
const renderEvaluatorList = () => {
if (!currentSupplier) {
return <div style={{ textAlign: 'center', padding: '20px 0' }}></div>;
}
if (!currentSupplier.evaluators || currentSupplier.evaluators.length === 0) {
return (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
&quot;&quot;
</div>
);
}
return (
<List
itemLayout="horizontal"
dataSource={currentSupplier.evaluators}
renderItem={(item: PersonnelItem) => (
<List.Item>
<List.Item.Meta
title={item.name}
description={`${item.department || '未知部门'}`}
/>
</List.Item>
)}
/>
);
};
return (
<Modal
title={`${mode === ModalMode.SELECT ? '选择' : '查看'}评价人员 - ${
currentSupplier?.supplierName || ''
}`}
visible={visible}
onCancel={onCancel}
footer={
mode === ModalMode.VIEW
? [
<Button key="close" onClick={onCancel}>
</Button>,
]
: null
}
width={700}
destroyOnClose={false}
>
{mode === ModalMode.SELECT ? (
<EvaluateTaskPersonnelSelector
key={`personnel-selector-${currentSupplier?.id || 'new'}-${visible}`}
onSelect={handleSelect}
selectedPersonnel={localSelectedPersonnel}
/>
) : (
renderEvaluatorList()
)}
</Modal>
);
};
export default SupplierEvaluatorModal;

View File

@ -0,0 +1,110 @@
import React, { useEffect } from 'react';
import { Table, Space, Button, Tag, Modal,Tooltip } from 'antd';
import type { SupplierItem } from '@/servers/types/evaluator';
interface SupplierTableProps {
suppliers: SupplierItem[]; // 供应商数据列表
selectedRowKeys: React.Key[]; // 选中的行keys
onSelectChange: (selectedRowKeys: React.Key[]) => void; // 选择行变化的回调
onViewEvaluators: (supplier: SupplierItem) => void; // 查看评价人员的回调
onSelectEvaluators: (supplier: SupplierItem) => void; // 选择评价人员的回调
onDeleteSupplier: (key: string) => void; // 删除供应商的回调
}
const SupplierTable: React.FC<SupplierTableProps> = ({
suppliers,
selectedRowKeys,
onSelectChange,
onViewEvaluators,
onSelectEvaluators,
onDeleteSupplier,
}) => {
// 表格行选择配置
const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
};
// 删除确认对话框
const showDeleteConfirm = (record: SupplierItem) => {
Modal.confirm({
title: '确定要删除此供应商吗?',
content: `供应商: ${record.supplierName}${
record.evaluatorCount > 0 ? `,将同时删除 ${record.evaluatorCount} 名关联的评价人员` : ''
}`,
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => onDeleteSupplier(record.id),
});
};
// 表格列定义
const columns = [
{
title: '供应商名称', // 列标题
dataIndex: 'supplierName', // 数据字段名
key: 'supplierName', // 列的唯一标识
},
{
title: '统一社会信用代码',
dataIndex: 'socialCreditCode',
key: 'socialCreditCode',
},
{
title: '品类',
dataIndex: 'categoryName',
key: 'categoryName',
render: (categoryName: string) => (
<Tooltip placement="topLeft" title={categoryName}>
{categoryName || '-'}
</Tooltip>
),
},
{
title: '准入部门',
dataIndex: 'department',
key: 'department',
},
{
title: '评价人员数',
align: 'center' as const, // 列对齐方式
dataIndex: 'evaluatorCount', // 评价人员数量字段
key: 'evaluatorCount',
},
{
title: '操作',
key: 'action',
render: (_: any, record: SupplierItem) => (
<Space>
<Button
type="link"
onClick={() => {
onViewEvaluators(record);
}}
>
</Button>
<Button type="link" onClick={() => onSelectEvaluators(record)}>
</Button>
<Button type="link" onClick={() => showDeleteConfirm(record)}>
</Button>
</Space>
),
},
];
return (
<Table
rowSelection={rowSelection} // 行选择配置
columns={columns} // 列配置
dataSource={suppliers} // 数据源
pagination={false} // 分页配置,这里禁用了分页
rowKey="id" // 行的唯一标识字段
/>
);
};
export default SupplierTable;

View File

@ -0,0 +1,50 @@
import React from 'react';
import { Modal, Form, Row, Col, InputNumber } from 'antd';
import type { WeightUnit } from '@/servers/types/evaluator';
interface WeightSettingModalProps {
visible: boolean;
onCancel: () => void;
onOk: () => void;
weightUnits: WeightUnit[];
form: any;
}
const WeightSettingModal: React.FC<WeightSettingModalProps> = ({
visible,
onCancel,
onOk,
weightUnits,
form,
}) => {
return (
<Modal
title="设置评分单位权重"
visible={visible}
onOk={onOk}
onCancel={onCancel}
>
<Form form={form} layout="horizontal">
<Row gutter={16}>
{weightUnits.map((unit) => (
<Col span={12} key={unit.id}>
<Form.Item
key={unit.id}
label={unit.name}
name={['weightUnits', unit.id]}
rules={[
{ required: true, message: '请输入权重值' },
{ type: 'number', min: 0, message: '请输入大于等于0的数值' },
]}
>
<InputNumber min={0} max={100} style={{ width: '100%' }} />
</Form.Item>
</Col>
))}
</Row>
</Form>
</Modal>
);
};
export default WeightSettingModal;

View File

@ -0,0 +1,15 @@
import SupplierTable from './SupplierTable';
import BatchEvaluatorModal from './BatchEvaluatorModal';
import SupplierEvaluatorModal from './SupplierEvaluatorModal';
import WeightSettingModal from './WeightSettingModal';
// 日志组件版本
console.log('EvaluatorComponents version: 1.0.1');
export {
SupplierTable,
BatchEvaluatorModal,
SupplierEvaluatorModal,
WeightSettingModal,
// 导出的所有组件
};

View File

@ -1,421 +1,359 @@
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Card, Button, Table, Space, Modal, Tag, Tooltip, Input, Form, InputNumber } from 'antd';
import { UserOutlined, SettingOutlined } from '@ant-design/icons';
import { Card, Button, Space, Form } from 'antd';
import styles from '../supplierTaskManageAdd.less';
import EvaluateTaskPersonnelSelector, { PersonnelItem } from '@/components/EvaluateTaskPersonnelSelector/EvaluateTaskPersonnelSelector';
import {
SupplierTable,
BatchEvaluatorModal,
SupplierEvaluatorModal,
WeightSettingModal,
} from './EvaluatorComponents';
import { ModalMode } from '@/servers/types/evaluator';
import type { PersonnelItem, SupplierItem, WeightUnit } from '@/servers/types/evaluator';
interface EvaluatorSelectStepProps {
formData: any;
onFormDataChange: (data: any) => void;
formData: any; // 从上层组件传递过来的表单数据
onFormDataChange: (data: any) => void; // 表单数据变更回调函数
}
interface SupplierItem {
key: string;
supplierName: string;
socialCreditCode: string;
category: string;
department: string;
evaluatorCount: number;
evaluators?: PersonnelItem[];
}
const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(
({ formData, onFormDataChange }, ref) => {
// 选中的供应商行的key列表用于批量操作
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
interface WeightUnit {
id: string;
name: string;
weight: number;
}
// 供应商列表数据,包含评价人员信息
const [suppliers, setSuppliers] = useState<SupplierItem[]>([]);
const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(({ formData, onFormDataChange }, ref) => {
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
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);
const [weightUnits, setWeightUnits] = useState<WeightUnit[]>([
{ id: '1', name: '集运', weight: 0 },
{ id: '2', name: '散运', weight: 0 },
{ id: '3', name: '能源', weight: 0 },
{ id: '4', name: '特运', weight: 0 },
{ id: '5', name: '化运', weight: 0 },
]);
const [form] = Form.useForm();
// 批量选择模态框的可见性控制
const [batchSelectModalVisible, setBatchSelectModalVisible] = useState(false);
// 暴露表单方法给父组件
useImperativeHandle(ref, () => ({
validateFields: () => {
// 自定义验证逻辑
if (suppliers.length === 0) {
return Promise.reject('请至少添加一个供应商');
// 权重设置模态框的可见性控制
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 [weightUnits, setWeightUnits] = useState<WeightUnit[]>([]);
// 表单实例,用于权重设置
const [form] = Form.useForm();
// 暴露表单方法给父组件
useImperativeHandle(ref, () => ({
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();
},
getFieldsValue: () => {
// 构建评价人员列表
const indicatorList = suppliers.flatMap(
(supplier) =>
supplier.evaluators?.map((evaluator: PersonnelItem) => ({
userId: evaluator.id,
type: 0, // type 评价类型(默认0 按评价单 ,当用户关联了指标则为 :1 按指标)
indicatorIds: [],
})) || [],
);
// 构建供应商ID列表
const supplierIds = suppliers.map((supplier) => ({
id: supplier.id,
userIds: supplier.evaluators?.map((e: PersonnelItem) => e.id) || [],
}));
return {
indicatorList,
supplierIds,
suppliersWithEvaluators: suppliers,
weightUnits,
};
},
setFieldsValue: (values: any) => {
if (values.suppliersWithEvaluators) {
debugger;
setSuppliers(values.suppliersWithEvaluators);
}
if (values.weightUnits) {
setWeightUnits(values.weightUnits);
}
},
}));
// 从上一步获取供应商数据
useEffect(() => {
if (formData.selectedSuppliers && formData.selectedSuppliers.length > 0) {
// 转换上一步的供应商数据,添加评价人员数量字段
const suppliersWithEvaluators = formData.selectedSuppliers.map((supplier: any) => {
// 确保evaluators字段存在且为数组
const evaluators = supplier.evaluators || [];
return {
...supplier,
department: supplier.userDept || '采购部', // 假设部门数据,实际应该从上一步获取
evaluatorCount: evaluators.length,
evaluators: evaluators,
};
});
setSuppliers(suppliersWithEvaluators);
} else {
// 没有选择供应商,清空供应商列表
setSuppliers([]);
}
// 检查是否每个供应商都有评价人员
const hasNoEvaluator = suppliers.some(supplier =>
!supplier.evaluators || supplier.evaluators.length === 0
);
if (hasNoEvaluator) {
return Promise.reject('存在未分配评价人员的供应商');
// 初始化权重数据(如果有)
if (formData.WeightUnit && formData.WeightUnit.length > 0) {
setWeightUnits(formData.WeightUnit);
} else {
// 没有权重数据将在下面的useEffect中根据人员部门计算
setWeightUnits([]);
}
}, [formData]);
return Promise.resolve();
},
getFieldsValue: () => {
// 构建评价人员列表
const indicatorList = suppliers.flatMap(supplier =>
supplier.evaluators?.map(evaluator => ({
userId: evaluator.id,
type: 0, // 假设按评价单评价
indicatorIds: []
})) || []
// 当选择的人员变化时,更新权重单位列表
useEffect(() => {
// 抽取所有评价人员的部门
const allDepartments: string[] = [];
suppliers.forEach((supplier) => {
if (supplier.evaluators && supplier.evaluators.length > 0) {
supplier.evaluators.forEach((evaluator) => {
if (evaluator.department) {
allDepartments.push(evaluator.department);
}
});
}
});
// 去重部门列表
const uniqueDepartments = [...new Set(allDepartments)];
// 如果有部门数据,生成权重单位列表
if (uniqueDepartments.length > 0) {
const newWeightUnits: WeightUnit[] = uniqueDepartments.map((dept, index) => ({
id: (index + 1).toString(),
name: dept,
weight: 0, // 默认权重为0
}));
// 更新权重单位列表,保留原有权重值
setWeightUnits((prevUnits) => {
const prevUnitsMap = new Map(prevUnits.map((unit) => [unit.name, unit.weight]));
return newWeightUnits.map((unit) => ({
...unit,
weight: prevUnitsMap.get(unit.name) || 0, // 如果有原来的权重值则保留
}));
});
}
}, [suppliers]);
// 更新表单数据
const updateFormData = (updatedData: any) => {
// // 构建评价人员列表
const indicatorList = suppliers.flatMap(
(supplier) =>
supplier.evaluators?.map((evaluator: PersonnelItem) => ({
userId: evaluator.id,
type: 0, // 默认按评价单评价 (没有指派分工),如果指派了 (就 1 按指标)
indicatorIds: [], // 指标id集合
})) || [],
);
// 构建供应商ID列表
const supplierIds = suppliers.map(supplier => ({
id: supplier.key,
userIds: supplier.evaluators?.map(e => e.id) || []
const supplierIds = suppliers.map((supplier) => ({
id: supplier.id,
userIds: supplier.evaluators?.map((e: PersonnelItem) => e.id) || [],
}));
return {
onFormDataChange({
...updatedData,
indicatorList,
supplierIds,
suppliersWithEvaluators: suppliers
};
},
setFieldsValue: (values: any) => {
if (values.suppliersWithEvaluators) {
setSuppliers(values.suppliersWithEvaluators);
weightUnits,
});
};
// 处理批量选择
const handleBatchSelect = () => {
if (selectedRowKeys.length === 0) return;
setBatchSelectModalVisible(true);
};
// 处理设置评分单位权重
const handleWeightSetting = () => {
// 设置初始表单值
form.setFieldsValue({
weightUnits: weightUnits.reduce((acc, unit) => {
acc[unit.id] = unit.weight;
return acc;
}, {} as Record<string, number>),
});
setWeightSettingModalVisible(true);
};
// 保存权重设置
const handleSaveWeights = () => {
form.validateFields().then((values) => {
const updatedWeightUnits = weightUnits.map((unit) => ({
...unit,
weight: values.weightUnits[unit.id],
}));
setWeightUnits(updatedWeightUnits);
updateFormData({ weightUnits: updatedWeightUnits });
setWeightSettingModalVisible(false);
});
};
// 处理选择评价人员
const handleSelectEvaluators = (supplier: SupplierItem) => {
setCurrentSupplier(supplier);
setModalMode(ModalMode.SELECT);
setEvaluatorModalVisible(true);
};
// 处理查看评价人员
const handleViewEvaluators = (supplier: SupplierItem) => {
// 查找完整的供应商数据包括evaluators
const fullSupplier = suppliers.find((s) => s.id === supplier.id);
if (fullSupplier) {
setCurrentSupplier(fullSupplier);
} else {
setCurrentSupplier(supplier);
}
if (values.weightUnits) {
setWeightUnits(values.weightUnits);
}
},
}));
// 从上一步获取供应商数据
useEffect(() => {
if (formData.selectedSuppliers) {
// 转换上一步的供应商数据,添加评价人员数量字段
const suppliersWithEvaluators = formData.selectedSuppliers.map((supplier: any) => ({
...supplier,
department: supplier.department || '采购部', // 假设部门数据,实际应该从上一步获取
evaluatorCount: supplier.evaluators?.length || 0,
}));
setSuppliers(suppliersWithEvaluators);
} else {
// 如果没有从上一步获取到数据,使用模拟数据
const mockSuppliers: SupplierItem[] = [
{ key: '1', supplierName: '供应商A', socialCreditCode: '123456789012345678', category: '润滑油', department: '采购部', evaluatorCount: 2, evaluators: [
{ id: '1', name: '张三', department: '采购部' },
{ id: '2', name: '李四', department: '技术部' }
] },
{ key: '2', supplierName: '供应商B', socialCreditCode: '123456789012345679', category: '燃油', department: '技术部', evaluatorCount: 0 },
{ key: '3', supplierName: '供应商C', socialCreditCode: '123456789012345680', category: '备件', department: '质量部', evaluatorCount: 1, evaluators: [
{ id: '3', name: '王五', department: '质量部' }
] },
{ key: '4', supplierName: '供应商D', socialCreditCode: '123456789012345681', category: '计算机', department: '生产部', evaluatorCount: 0 },
];
setSuppliers(mockSuppliers);
}
setModalMode(ModalMode.VIEW);
setEvaluatorModalVisible(true);
};
// 初始化权重数据(如果有)
if (formData.weightUnits) {
setWeightUnits(formData.weightUnits);
}
}, [formData]);
// 处理评价人员选择确认
const handleEvaluatorSelect = (selectedEvaluators: PersonnelItem[]) => {
if (!currentSupplier) return;
// 更新表单数据
const updateFormData = (updatedData: any) => {
// 构建评价人员列表
const indicatorList = suppliers.flatMap(supplier =>
supplier.evaluators?.map(evaluator => ({
userId: evaluator.id,
type: 0, // 假设按评价单评价
indicatorIds: []
})) || []
);
const updatedSuppliers = suppliers.map((supplier) => {
if (supplier.id === currentSupplier.id) {
const updated = {
...supplier,
evaluators: selectedEvaluators,
evaluatorCount: selectedEvaluators.length,
};
return updated;
}
return supplier;
});
// 构建供应商ID列表
const supplierIds = suppliers.map(supplier => ({
id: supplier.key,
userIds: supplier.evaluators?.map(e => e.id) || []
}));
setSuppliers(updatedSuppliers);
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
setEvaluatorModalVisible(false);
};
onFormDataChange({
...updatedData,
indicatorList,
supplierIds
});
};
// 处理批量选择评价人员确认
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);
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
setBatchSelectModalVisible(false);
};
// 处理批量选择
const handleBatchSelect = () => {
if (selectedRowKeys.length === 0) return;
setBatchSelectModalVisible(true);
};
// 处理删除供应商
const handleDeleteSupplier = (key: string) => {
const updatedSuppliers = suppliers.filter((item) => item.id !== key);
setSuppliers(updatedSuppliers);
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
// 更新选中行,移除已删除的供应商
setSelectedRowKeys((prevKeys) => prevKeys.filter((k) => k !== key));
};
// 处理设置评分单位权重
const handleWeightSetting = () => {
// 设置初始表单值
form.setFieldsValue({
weightUnits: weightUnits.reduce((acc, unit) => {
acc[unit.id] = unit.weight;
return acc;
}, {} as Record<string, number>)
});
return (
<div className={styles.evaluatorSelectStep}>
<Card title="选择评价人员" bordered={false} className="inner-card">
<div className={styles.toolbar}>
<Space>
<Button
type="primary"
onClick={handleBatchSelect}
disabled={selectedRowKeys.length === 0}
>
</Button>
<Button onClick={handleWeightSetting} disabled={weightUnits.length === 0}>
</Button>
</Space>
</div>
setWeightSettingModalVisible(true);
};
// 保存权重设置
const handleSaveWeights = () => {
form.validateFields().then(values => {
const updatedWeightUnits = weightUnits.map(unit => ({
...unit,
weight: values.weightUnits[unit.id]
}));
setWeightUnits(updatedWeightUnits);
updateFormData({ weightUnits: updatedWeightUnits });
setWeightSettingModalVisible(false);
});
};
// 处理选择评价人员
const handleSelectEvaluators = (supplier: SupplierItem) => {
setCurrentSupplier(supplier);
setEvaluatorModalVisible(true);
};
// 处理评价人员选择确认
const handleEvaluatorSelect = (selectedEvaluators: PersonnelItem[]) => {
if (!currentSupplier) return;
const updatedSuppliers = suppliers.map(supplier => {
if (supplier.key === currentSupplier.key) {
return {
...supplier,
evaluators: selectedEvaluators,
evaluatorCount: selectedEvaluators.length
};
}
return supplier;
});
setSuppliers(updatedSuppliers);
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
setEvaluatorModalVisible(false);
};
// 处理批量选择评价人员确认
const handleBatchEvaluatorSelect = (selectedEvaluators: PersonnelItem[]) => {
if (selectedRowKeys.length === 0) return;
const updatedSuppliers = suppliers.map(supplier => {
if (selectedRowKeys.includes(supplier.key)) {
return {
...supplier,
evaluators: selectedEvaluators,
evaluatorCount: selectedEvaluators.length
};
}
return supplier;
});
setSuppliers(updatedSuppliers);
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
setBatchSelectModalVisible(false);
};
// 处理删除供应商
const handleDeleteSupplier = (key: string) => {
const updatedSuppliers = suppliers.filter(item => item.key !== key);
setSuppliers(updatedSuppliers);
updateFormData({ suppliersWithEvaluators: updatedSuppliers });
};
// 删除确认对话框
const showDeleteConfirm = (record: SupplierItem) => {
Modal.confirm({
title: '确定要删除此供应商吗?',
content: `供应商: ${record.supplierName}`,
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => handleDeleteSupplier(record.key),
});
};
// 表格行选择配置
const rowSelection = {
selectedRowKeys,
onChange: (keys: React.Key[]) => {
setSelectedRowKeys(keys);
}
};
// 表格列定义
const columns = [
{
title: '供应商名称',
dataIndex: 'supplierName',
key: 'supplierName',
},
{
title: '统一社会信用代码',
dataIndex: 'socialCreditCode',
key: 'socialCreditCode',
},
{
title: '品类',
dataIndex: 'category',
key: 'category',
render: (text: string) => <Tag color="blue">{text}</Tag>,
},
{
title: '准入部门',
dataIndex: 'department',
key: 'department',
},
{
title: '评价人员数',
dataIndex: 'evaluatorCount',
key: 'evaluatorCount',
render: (count: number) => (
<span style={{ color: count === 0 ? 'red' : 'inherit' }}>
{count}
</span>
),
},
{
title: '操作',
key: 'action',
render: (_: any, record: SupplierItem) => (
<>
<Button
type="link"
onClick={() => handleSelectEvaluators(record)}
>
</Button>
{record.evaluatorCount > 0 && (
<Button
type="link"
onClick={() => handleSelectEvaluators(record)}
>
</Button>
{suppliers.length === 0 ? (
<div style={{ textAlign: 'center', padding: '30px 0', color: '#999' }}>
</div>
) : (
<SupplierTable
suppliers={suppliers}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
onViewEvaluators={handleViewEvaluators}
onSelectEvaluators={handleSelectEvaluators}
onDeleteSupplier={handleDeleteSupplier}
/>
)}
<Button
type="link"
onClick={() => showDeleteConfirm(record)}
>
</Button>
</>
),
},
];
return (
<div className={styles.evaluatorSelectStep}>
<Card title="选择评价人员" bordered={false} className="inner-card">
<div className={styles.toolbar}>
<Space>
<Button
type="primary"
icon={<UserOutlined />}
onClick={handleBatchSelect}
disabled={selectedRowKeys.length === 0}
>
</Button>
<Button
icon={<SettingOutlined />}
onClick={handleWeightSetting}
>
</Button>
</Space>
</div>
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={suppliers}
pagination={false}
rowKey="key"
/>
{/* 批量选择评价人员弹窗 */}
<Modal
title="批量选择评价人员"
visible={batchSelectModalVisible}
onCancel={() => setBatchSelectModalVisible(false)}
footer={null}
width={700}
>
<EvaluateTaskPersonnelSelector
{/* 批量选择评价人员弹窗 */}
<BatchEvaluatorModal
visible={batchSelectModalVisible}
onCancel={() => setBatchSelectModalVisible(false)}
onSelect={handleBatchEvaluatorSelect}
selectedPersonnel={[]}
/>
</Modal>
{/* 单个供应商选择评价人员弹窗 */}
<Modal
title={`选择评价人员 - ${currentSupplier?.supplierName || ''}`}
visible={evaluatorModalVisible}
onCancel={() => setEvaluatorModalVisible(false)}
footer={null}
width={700}
>
<EvaluateTaskPersonnelSelector
{/* 单个供应商评价人员弹窗 */}
<SupplierEvaluatorModal
visible={evaluatorModalVisible}
onCancel={() => setEvaluatorModalVisible(false)}
onSelect={handleEvaluatorSelect}
selectedPersonnel={currentSupplier?.evaluators || []}
currentSupplier={currentSupplier}
mode={modalMode}
/>
</Modal>
{/* 权重设置弹窗 */}
<Modal
title="设置评分单位权重"
visible={weightSettingModalVisible}
onOk={handleSaveWeights}
onCancel={() => setWeightSettingModalVisible(false)}
>
<Form
{/* 权重设置弹窗 */}
<WeightSettingModal
visible={weightSettingModalVisible}
onCancel={() => setWeightSettingModalVisible(false)}
onOk={handleSaveWeights}
weightUnits={weightUnits}
form={form}
layout="vertical"
>
<Form.Item label="权重设置" required>
<p>100%</p>
{weightUnits.map(unit => (
<Form.Item
key={unit.id}
label={unit.name}
name={['weightUnits', unit.id]}
rules={[{ required: true, message: '请输入权重值' }]}
>
<InputNumber
min={0}
max={100}
formatter={value => `${value}%`}
parser={(value: string | undefined) => {
if (!value) return 0;
const num = Number(value.replace('%', ''));
return num;
}}
style={{ width: '100%' }}
/>
</Form.Item>
))}
</Form.Item>
</Form>
</Modal>
</Card>
</div>
);
});
/>
</Card>
</div>
);
},
);
export default EvaluatorSelectStep;

View File

@ -4,15 +4,15 @@ import styles from '../supplierTaskManageAdd.less';
import SupplierSelector from '@/components/SupplierSelector';
interface SupplierSelectStepProps {
formData: any;
onFormDataChange: (data: any) => void;
formData: any; // 从父组件传递的表单数据
onFormDataChange: (data: any) => void; // 表单数据变更的回调函数
}
interface SupplierItem {
id: string;
name: string;
supplierType: string;
[key: string]: any;
id: string; // 供应商ID
name: string; // 供应商名称
supplierType: string; // 供应商类型
[key: string]: any; // 其他可能的字段
}
const SupplierSelectStep = forwardRef<any, SupplierSelectStepProps>(({ formData, onFormDataChange }, ref) => {
@ -40,10 +40,19 @@ const SupplierSelectStep = forwardRef<any, SupplierSelectStepProps>(({ formData,
// 处理供应商选择
const handleSupplierSelect = (suppliers: SupplierItem[]) => {
// 确保每个供应商都有evaluators字段
const suppliersWithEvaluators = suppliers.map(supplier => ({
...supplier,
evaluators: supplier.evaluators || [], // 确保evaluators字段存在即使是空数组
evaluatorCount: supplier.evaluators?.length || 0 // 计算评价人员数量
}));
onFormDataChange({
...formData,
selectedSuppliers: suppliers,
supplierIds: suppliers.map(supplier => ({ id: supplier.id }))
selectedSuppliers: suppliersWithEvaluators,
supplierIds: suppliersWithEvaluators.map(supplier => ({ id: supplier.id }))
});
};