任务管理新增修改添加分工功能

This commit is contained in:
linxd
2025-06-27 11:38:36 +08:00
parent 527637cce3
commit db4533592f
15 changed files with 428 additions and 325 deletions

View File

@ -14,7 +14,10 @@ const { Search } = Input;
*/
interface EvaluateTaskPersonnelSelectorProps {
onSelect: (personnel: API.PersonnelItem[]) => void; // 选择确认后的回调函数
onClose: () => void; // 关闭回调函数
selectedPersonnel?: API.PersonnelItem[]; // 已选择的人员列表(用于回显)
filter?: boolean; // 是否过滤评价人员
filterUserIds?: string[]; // 过滤评价人员ID列表
}
/**
@ -32,7 +35,10 @@ interface EvaluateTaskPersonnelSelectorProps {
*/
const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps> = ({
onSelect,
selectedPersonnel = []
selectedPersonnel = [],
filter = false,
filterUserIds = [],
onClose,
}) => {
// 搜索关键词
const [keyword, setKeyword] = useState<string>('');
@ -66,6 +72,8 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
pageSize: 100, // 获取足够多的数据
},
keyword: keyword || undefined,
filter,
userIds: filter ? filterUserIds : undefined,
};
const response = await getUserList(params);
@ -80,6 +88,7 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
userDept: user.userDept, // 用户部门
userDeptId: user.userDeptId, // 用户部门ID
position: '', // API中没有提供职位信息
isSelected: user.isSelected,
}));
setPersonnel(personnelData);
@ -119,6 +128,9 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
setSelectedKeys(selectedRowKeys as string[]);
};
const onCancel = () => {
onClose();
};
/**
* 处理确认选择
*/
@ -141,7 +153,7 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
title: '部门',
dataIndex: 'userDept',
key: 'userDept',
},
}
];
@ -160,9 +172,14 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
</div>
</div>
<Table
// 如果 isSelected = true 则禁用勾选
rowSelection={{
selectedRowKeys: selectedKeys,
onChange: handleSelectChange,
getCheckboxProps: (record) => ({
// 如果 isSelected = true 则禁用勾选
disabled: record.isSelected === true,
}),
}}
columns={columns}
dataSource={personnel}
@ -173,7 +190,7 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
/>
<div className="selector-footer">
<Space>
<Button onClick={() => setSelectedKeys([])}></Button>
<Button onClick={onCancel}></Button>
<Button type="primary" onClick={handleConfirm}>
</Button>

View File

@ -6,7 +6,7 @@ import type {
TaskDetailResponse
} from '@/servers/dao/supplierEvaluateTask';
import type { TaskNotifyLowerUnits } from '@/dicts/supplierTaskDict';
import type { PersonnelItem } from '@/servers/dao/supplierEvaluateTask';
import type { PersonnelItem, IndicatorItem, SupplierItem } from '@/servers/dao/supplierEvaluateTask';
// Define the types for dva effects and reducers
type Effect = (action: { payload: any }, effects: { call: any; put: any; select: any }) => Generator<any, void, unknown>;
@ -22,7 +22,7 @@ export interface SupplierTaskModelState {
detailLoading: boolean; // 详情数据加载状态
taskFormData: Partial<TaskAddRequest>; // 任务表单数据
taskDetail: TaskDetailData | null; // 任务详情数据
userList: PersonnelItem[]; // 用户列表
mode: 'add' | 'edit' | 'division'; // 模式
}
/**
@ -39,6 +39,9 @@ export interface SupplierTaskModelType {
nextStep: Effect; // 下一步
prevStep: Effect; // 上一步
resetState: Effect; // 重置状态
setCurrentStep: Effect; // 设置当前步骤
setMode: Effect; // 设置模式
deleteUser: Effect; // 删除用户
};
reducers: {
saveCurrentStep: Reducer<SupplierTaskModelState>; // 保存当前步骤
@ -46,6 +49,7 @@ export interface SupplierTaskModelType {
saveDetailLoading: Reducer<SupplierTaskModelState>; // 保存详情加载状态
saveTaskFormData: Reducer<SupplierTaskModelState>; // 保存任务表单数据
saveTaskDetail: Reducer<SupplierTaskModelState>; // 保存任务详情数据
saveMode: Reducer<SupplierTaskModelState>; // 保存模式
};
}
@ -63,7 +67,7 @@ const SupplierTaskModel: SupplierTaskModelType = {
detailLoading: false, // 详情数据加载状态
taskFormData: {}, // 任务表单数据
taskDetail: null, // 任务详情数据
userList: [], // 用户列表
mode: 'add', // 模式
},
// 副作用处理函数
@ -94,6 +98,7 @@ const SupplierTaskModel: SupplierTaskModelType = {
evaluateYear: detail.evaluateYear || '',
categoryId: detail.categoryId || undefined,
// 供应商数据转换添加id和name字段用于UI展示
selectedSuppliers: detail.blackSupplierVos.map((item) => ({
...item,
@ -110,7 +115,6 @@ const SupplierTaskModel: SupplierTaskModelType = {
// 部门权重
taskDeptWeightList: detail.taskDeptWeightList || [],
//设置评价分工table回显 需处理
userList: detail.userList.map((user) => {
const matchedIndicator = detail.indicatorList?.find(
@ -124,21 +128,7 @@ const SupplierTaskModel: SupplierTaskModelType = {
};
}),
// 供应商与评价人员关联,用于分工步骤 需要以userList[]人员为维度,
// 关联出 indicatorList[]指标中的 userId,
// 关联出来的对象中的indicatorIds[]为指标id,
// 对象中的type不需要关注,只在保存时动态修改即可
suppliersWithEvaluators: detail.userList.map((user) => {
const matchedIndicator = detail.indicatorList?.find(
(indicator) => indicator.userId === user.userId
);
return {
...user,
name: user.userName,
id: user.userId,
indicatorIds: matchedIndicator?.indicatorIds || [],
};
}),
};
// 保存数据到状态
@ -255,14 +245,29 @@ const SupplierTaskModel: SupplierTaskModelType = {
}));
updatedFormData.selectedSuppliers = suppliersWithEvaluators;
}
// 处理评价人员更新 - 更新后要保留原有对象中的indicatorIds
if (payload.userList) {
const existingUserMap = new Map(
(taskFormData.userList || []).map((user: PersonnelItem) => [user.id || user.userId, user])
);
// 处理评价人员更新 - 保持suppliersWithEvaluators和selectedSuppliers同步
if (payload.suppliersWithEvaluators) {
const evaluatedSuppliers = payload.suppliersWithEvaluators;
updatedFormData.suppliersWithEvaluators = evaluatedSuppliers;
updatedFormData.selectedSuppliers = evaluatedSuppliers; // 同步更新selectedSuppliers
updatedFormData.userList = payload.userList.map((newUser: PersonnelItem) => {
const userId = newUser.id || newUser.userId;
const existing = existingUserMap.get(userId);
const indicatorIds =
newUser.indicatorIds && newUser.indicatorIds.length > 0
? newUser.indicatorIds
: existing?.indicatorIds || [];
return {
...newUser,
indicatorIds,
};
});
}
// 处理部门权重
if (payload.taskDeptWeightList) {
updatedFormData.taskDeptWeightList = payload.taskDeptWeightList;
@ -272,6 +277,49 @@ const SupplierTaskModel: SupplierTaskModelType = {
// 保存更新后的表单数据
yield put({ type: 'saveTaskFormData', payload: updatedFormData });
},
/**
* 删除用户
* @param payload.userId 用户ID
*/
*deleteUser({ payload }: { payload: { userIds: string[] } }, { put, select }: { put: any; select: any }) {
const { userIds } = payload;
if (!userIds || userIds.length === 0) return;
const userIdSet = new Set(userIds.filter(Boolean).map(String));
const { taskFormData } = (yield select((state: any) => state.supplierTaskManage)) as {
taskFormData: TaskAddRequest;
};
const updatedFormData = { ...taskFormData };
// 1. 删除 userList 中的用户
updatedFormData.userList = (updatedFormData.userList || []).filter(
(user: PersonnelItem) => !userIdSet.has(String(user.id || user.userId))
);
// 2. 删除 indicatorList(指标对象) 中该用户的指标
updatedFormData.indicatorList = (updatedFormData.indicatorList || []).filter(
(item: IndicatorItem) => !userIdSet.has(String(item.userId))
);
// 3. 删除 selectedSuppliers(供应商对象) 中 evaluator(评价人员对象) 对象
updatedFormData.selectedSuppliers = (updatedFormData.selectedSuppliers || [])
.map((supplier: SupplierItem) => {
const newEvaluators = (supplier.evaluators || []).filter(
(evaluator: PersonnelItem) => !userIdSet.has(String(evaluator.id))
);
return {
...supplier,
evaluators: newEvaluators,
};
})
.filter((supplier) => (supplier.evaluators || []).length > 0);
// 保存更新
yield put({ type: 'saveTaskFormData', payload: updatedFormData });
},
/**
* 下一步
@ -290,6 +338,12 @@ const SupplierTaskModel: SupplierTaskModelType = {
const { currentStep } = (yield select((state: any) => state.supplierTaskManage)) as { currentStep: number };
yield put({ type: 'saveCurrentStep', payload: currentStep - 1 });
},
/*
设置当前步骤
*/
*setCurrentStep({ payload }: { payload: number }, { put }: { put: any }) {
yield put({ type: 'saveCurrentStep', payload });
},
/**
* 重置状态
@ -307,6 +361,12 @@ const SupplierTaskModel: SupplierTaskModelType = {
payload: 0
});
},
/**
* 设置模式
*/
*setMode({ payload }: { payload: 'add' | 'edit' | 'division' }, { put }: { put: any }) {
yield put({ type: 'saveMode', payload });
},
},
// reducers用于更新状态
@ -317,6 +377,12 @@ const SupplierTaskModel: SupplierTaskModelType = {
saveCurrentStep(state, { payload }) {
return { ...state, currentStep: payload };
},
/**
* 保存模式
*/
saveMode(state, { payload }) {
return { ...state, mode: payload };
},
/**
* 保存加载状态
*/

View File

@ -36,8 +36,7 @@ const BasicInfoStepComponent = (props: BasicInfoStepProps) => {
// 暴露表单方法给父组件,使用 innerRef
useImperativeHandle(innerRef, () => ({
validateFields: () => form.validateFields(),
getFieldsValue: () => form.getFieldsValue(),
setFieldsValue: (values: any) => form.setFieldsValue(values),
// 删除不必要的方法因为现在使用Dva管理数据
}));
// 获取模板列表

View File

@ -14,13 +14,7 @@ import { getTemplateDetail } from '@/servers/api/supplierEvaluate';
import type { Dispatch } from 'umi';
import { connect } from 'umi';
import type { SupplierTaskModelState } from '@/models/supplierTaskManage';
// 评价指标类型定义
interface IndicatorItem {
id: string;
name: string;
description: string;
}
import type { IndicatorItem } from '@/servers/dao/supplierEvaluateTask';
// 组件接收的Props定义
interface DivisionStepProps {
@ -42,19 +36,11 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
const { supplierTaskManage, dispatch, innerRef } = props;
// 从 model 获取表单数据,避免通过 props 层层传递
const { taskFormData } = supplierTaskManage;
const { taskFormData, mode } = supplierTaskManage;
// 从上一步获取的评价人员列表
const [evaluators, setEvaluators] = useState<PersonnelItem[]>([]);
// 评价人员指标分配数据
const indicatorAssignments = useRef<{
[userId: string]: {
type: EvaluateType;
indicatorIds: string[];
};
}>({});
// 选中的行keys
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
@ -88,27 +74,14 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
// 查看模式下的过滤后指标数据
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]);
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[]) => {
@ -226,34 +199,55 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
);
return indicatorNdListIds;
};
// 处理指标,将处理后的指标放到dva中,同步处理userList,展示table
const handleIndicatorAssignment = (indicatorNdListIds: string[]) => {
// 读取dva中的indicatorList
const indicatorList = JSON.parse(JSON.stringify(taskFormData?.indicatorList));
// 将指标id塞到当前激活的评价人员中
indicatorList?.map((item: any) => {
// 判断当前激活的评价人员和选择评价人构建的userId一直
if (item.userId === currentUserId) {
item.indicatorIds = [...new Set([...item.indicatorIds, ...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: IndicatorItem) => {
if (item.userId === userId) {
item.indicatorIds = [...new Set([...(item.indicatorIds || []), ...indicatorNdListIds])];
}
});
// 构建userList带指标id 为了表单回显
const userList = JSON.parse(JSON.stringify(taskFormData?.userList));
userList?.map((item: any) => {
if (item.id === currentUserId) {
// 更新userList
userList.forEach((item: PersonnelItem) => {
if (item.id === userId) {
item.indicatorIds = indicatorNdListIds;
}
});
});
// 只调用一次updateFormData
updateFormData({
indicatorList,
userList,
});
};
// 保存指标分配
const handleSaveIndicatorAssignment = () => {
if (!currentUserId) {
message.warning('未选择评价人员');
return;
}
// 将选择回来的指标提取二级指标id
const indicatorNdListIds = getIndicatorNdListIds(selectedTemplateItems);
handleIndicatorAssignment(indicatorNdListIds, [currentUserId]);
setTemplateViewModalVisible(false);
message.success('已设置评价人员指标分工');
};
// 批量设置指标分工
const handleBatchSetDivision = () => {
// 将选择回来的指标提取二级指标id
const indicatorNdListIds = getIndicatorNdListIds(batchSelectedTemplateItems);
handleIndicatorAssignment(indicatorNdListIds);
const userIds = selectedRowKeys.map((key) => key.toString());
handleIndicatorAssignment(indicatorNdListIds, userIds);
setBatchTemplateModalVisible(false);
message.success(`已为${selectedRowKeys.length}名评价人员设置分工`);
};
@ -278,19 +272,6 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
setSelectedTemplateItems(selectedItems);
};
// 保存指标分配
const handleSaveIndicatorAssignment = () => {
if (!currentUserId) {
message.warning('未选择评价人员');
return;
}
// 将选择回来的指标提取二级指标id
const indicatorNdListIds = getIndicatorNdListIds(selectedTemplateItems);
handleIndicatorAssignment(indicatorNdListIds);
setTemplateViewModalVisible(false);
message.success('已设置评价人员指标分工');
};
// 查看评价人员的指标分工
const handleViewAssignment = (person: PersonnelItem) => {
const assignment = person.indicatorIds;
@ -329,35 +310,23 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
// 更新评价人员列表
setEvaluators((prev) => prev.filter((e) => e.id !== userId));
// 更新指标分配数据
const newAssignments = { ...indicatorAssignments.current };
delete newAssignments[userId];
indicatorAssignments.current = newAssignments;
//更新dva中的userList
dispatch({
type: 'supplierTaskManage/deleteUser',
payload: {
userIds: [userId],
},
});
message.success('已删除评价人员');
},
});
};
// 初始化从formData中提取指标分配数据
useEffect(() => {
if (taskFormData.indicatorList && taskFormData.indicatorList.length > 0) {
// 如果已有指标分配数据,直接使用
const assignments: any = {};
taskFormData.indicatorList.forEach((item: any) => {
assignments[item.userId] = {
type: item.type,
indicatorIds: item.indicatorIds || [],
};
});
indicatorAssignments.current = assignments;
}
}, [taskFormData.indicatorList]);
// 从上一步获取评价人员列表 - 避免频繁更新
useEffect(() => {
if (!taskFormData.userList) return;
setEvaluators(taskFormData.userList);
setEvaluators(taskFormData.userList as PersonnelItem[]);
}, [taskFormData.userList]);
// 暴露给父组件的方法
@ -401,8 +370,7 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
title: '是否设置分工',
key: 'hasDivision',
render: (_: any, record: PersonnelItem) => {
const assignment = indicatorAssignments.current[record.id];
if (!assignment || assignment.indicatorIds.length === 0)
if (!record.indicatorIds || record.indicatorIds.length === 0)
return <Tag color="red"></Tag>;
return <Tag color="green"></Tag>;
},
@ -412,22 +380,31 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
key: 'action',
render: (_: any, record: PersonnelItem) => (
<Space size="middle">
{!record.isSelected && (
<>
<Button type="link" onClick={() => handleAssignIndicators(record.id)}>
</Button>
<Button type="link" onClick={() => handleViewAssignment(record)}>
</Button>
<Button type="link" onClick={() => handleRemoveEvaluator(record.id)}>
</Button>
</>
)}
<Button type="link" onClick={() => handleViewAssignment(record)}>
</Button>
</Space>
),
},
];
const rowSelection = {
selectedRowKeys,
onChange: handleSelectChange,
};
return (
<div>
{mode !== 'division' && (
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
@ -437,13 +414,11 @@ const DivisionStepComponent = (props: DivisionStepProps) => {
</Button>
</div>
)}
<Table
rowKey="id"
rowSelection={{
selectedRowKeys,
onChange: handleSelectChange,
}}
rowSelection={mode === 'division' ? undefined : rowSelection}
columns={columns}
dataSource={evaluators}
pagination={false}

View File

@ -8,6 +8,8 @@ interface BatchEvaluatorModalProps {
onCancel: () => void;
onSelect: (selectedEvaluators: PersonnelItem[]) => void;
selectedPersonnel?: PersonnelItem[];
filter?: boolean;
filterUserIds?: string[];
}
const BatchEvaluatorModal: React.FC<BatchEvaluatorModalProps> = ({
@ -15,6 +17,8 @@ const BatchEvaluatorModal: React.FC<BatchEvaluatorModalProps> = ({
onCancel,
onSelect,
selectedPersonnel = [],
filter,
filterUserIds,
}) => {
return (
<Modal
@ -28,6 +32,9 @@ const BatchEvaluatorModal: React.FC<BatchEvaluatorModalProps> = ({
<EvaluateTaskPersonnelSelector
onSelect={onSelect}
selectedPersonnel={selectedPersonnel}
filter={filter}
filterUserIds={filterUserIds}
onClose={onCancel}
/>
</Modal>
);

View File

@ -10,6 +10,8 @@ interface SupplierEvaluatorModalProps {
onSelect: (personnel: PersonnelItem[]) => void; // 选择人员后的回调函数
currentSupplier: SupplierItem | null; // 当前操作的供应商对象
mode: ModalMode; // 弹窗模式SELECT(选择) 或 VIEW(查看)
filter?: boolean; // 是否过滤评价人员
filterUserIds?: string[]; // 过滤评价人员ID列表
}
const SupplierEvaluatorModal: React.FC<SupplierEvaluatorModalProps> = ({
@ -18,6 +20,8 @@ const SupplierEvaluatorModal: React.FC<SupplierEvaluatorModalProps> = ({
onSelect,
currentSupplier,
mode,
filter,
filterUserIds,
}) => {
// 本地保存当前选中的人员,确保在弹窗打开/关闭时能正确处理数据
const [localSelectedPersonnel, setLocalSelectedPersonnel] = useState<PersonnelItem[]>([]);
@ -95,7 +99,10 @@ const SupplierEvaluatorModal: React.FC<SupplierEvaluatorModalProps> = ({
<EvaluateTaskPersonnelSelector
key={`personnel-selector-${currentSupplier?.id || 'new'}-${visible}`}
onSelect={handleSelect}
filter={filter}
filterUserIds={filterUserIds}
selectedPersonnel={localSelectedPersonnel}
onClose={onCancel}
/>
) : (
renderEvaluatorList()

View File

@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { Table, Space, Button, Tag, Modal,Tooltip } from 'antd';
import { Table, Space, Button, Tag, Modal, Tooltip } from 'antd';
import type { SupplierItem } from '@/servers/types/evaluator';
interface SupplierTableProps {
@ -9,6 +9,7 @@ interface SupplierTableProps {
onViewEvaluators: (supplier: SupplierItem) => void; // 查看评价人员的回调
onSelectEvaluators: (supplier: SupplierItem) => void; // 选择评价人员的回调
onDeleteSupplier: (key: string) => void; // 删除供应商的回调
mode?: string; // 模式
}
const SupplierTable: React.FC<SupplierTableProps> = ({
@ -18,6 +19,7 @@ const SupplierTable: React.FC<SupplierTableProps> = ({
onViewEvaluators,
onSelectEvaluators,
onDeleteSupplier,
mode,
}) => {
// 表格行选择配置
const rowSelection = {
@ -88,9 +90,13 @@ const SupplierTable: React.FC<SupplierTableProps> = ({
<Button type="link" onClick={() => onSelectEvaluators(record)}>
</Button>
{mode !== 'division' && (
<>
<Button type="link" onClick={() => showDeleteConfirm(record)}>
</Button>
</>
)}
</Space>
),
},
@ -98,7 +104,7 @@ const SupplierTable: React.FC<SupplierTableProps> = ({
return (
<Table
rowSelection={rowSelection} // 行选择配置
rowSelection={mode === 'division' ? undefined : rowSelection} // 行选择配置
columns={columns} // 列配置
dataSource={suppliers} // 数据源
pagination={false} // 分页配置,这里禁用了分页

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import React, { useState, useEffect, forwardRef, useImperativeHandle, useRef } from 'react';
import { Card, Button, Space, Form } from 'antd';
import styles from '../supplierTaskManageAdd.less';
import {
@ -38,7 +38,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
const { supplierTaskManage, dispatch, innerRef } = props;
// 从 model 获取表单数据,避免通过 props 层层传递
const { taskFormData } = supplierTaskManage;
const { taskFormData, mode } = supplierTaskManage;
// 选中的供应商行的key列表用于批量操作
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
@ -66,7 +66,15 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
// 表单实例,用于权重设置
const [form] = Form.useForm();
const [filterUserIds, setFilterUserIds] = useState<string[]>([]);
useEffect(() => {
if (mode === 'division' && taskFormData.userList && taskFormData.userList.length > 0) {
const filterUserIdsaa = taskFormData.userList
.map((user: PersonnelItem) => (user.isSelected === true ? user.id : null))
.filter((id: string | null) => id !== null);
setFilterUserIds(filterUserIdsaa);
}
}, [mode, taskFormData.userList]);
/**
* 暴露表单方法给父组件
* 包含验证、获取和设置表单数据的方法
@ -88,44 +96,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
}
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,
taskDeptWeightList,
};
},
// 设置表单数据的方法,通常在编辑模式下使用
setFieldsValue: (values: any) => {
if (values.suppliersWithEvaluators) {
setSuppliers(values.suppliersWithEvaluators);
}
if (values.taskDeptWeightList) {
setTaskDeptWeightList(values.taskDeptWeightList);
}
},
}));
/**
@ -137,7 +108,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
if (taskFormData.selectedSuppliers && taskFormData.selectedSuppliers.length > 0) {
// 转换上一步的供应商数据,添加评价人员数量字段
const suppliersWithEvaluators = taskFormData.selectedSuppliers.map(
(supplier: SupplierItem) => {
(supplier) => {
// 确保evaluators字段存在且为数组
const evaluators = supplier.evaluators || [];
return {
@ -226,19 +197,24 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
userIds: supplier.evaluators?.map((e: PersonnelItem) => e.id) || [],
}));
// 构建userList 并去重
const userList = Array.from(
new Map(
// 构建userList 并去重,确保保留 isSelected 为 true 的对象
const userMap = new Map();
suppliersWithEvaluators
.flatMap(s => s.evaluators || [])
.map(user => [user.id, user])
).values()
);
.flatMap((s) => s.evaluators || [])
.forEach((user) => {
// 如果已存在此ID的用户且当前用户isSelected为true或者Map中不存在此用户则更新/添加
if (!userMap.has(user.id) || user.isSelected) {
userMap.set(user.id, user);
}
});
const userList = Array.from(userMap.values());
// 构建评价人员列表
const indicatorList = userList.map((user) => ({
...user,
userId: user.id,
type: 0, // 默认按评价单评价 (没有指派分工),如果指派了 (就 1 按指标)
indicatorIds: [], // 指标id集合
indicatorIds: user.indicatorIds || [], // 指标id集合
}));
// 通过dispatch更新model中的数据
@ -251,7 +227,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
indicatorList,
userList,
supplierIds,
suppliersWithEvaluators: suppliersWithEvaluators,
selectedSuppliers: suppliersWithEvaluators,
},
});
};
@ -342,7 +318,6 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
*/
const handleEvaluatorSelect = (selectedEvaluators: PersonnelItem[]) => {
if (!currentSupplier) return;
// 更新当前供应商的评价人员列表
const updatedSuppliers = suppliers.map((supplier) => {
if (supplier.id === currentSupplier.id) {
@ -420,6 +395,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
<div className={styles.evaluatorSelectStep}>
<Card title="选择评价人员" bordered={false} className="inner-card">
{/* 工具栏区域 */}
{mode !== 'division' && (
<div className={styles.toolbar}>
<Space>
<Button
@ -434,6 +410,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
</Button>
</Space>
</div>
)}
{/* 供应商表格区域 */}
{suppliers.length === 0 ? (
@ -443,6 +420,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
) : (
<SupplierTable
suppliers={suppliers}
mode={mode}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
onViewEvaluators={handleViewEvaluators}
@ -455,6 +433,8 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
<BatchEvaluatorModal
visible={batchSelectModalVisible}
onCancel={() => setBatchSelectModalVisible(false)}
filter={mode === 'division'}
filterUserIds={filterUserIds}
onSelect={handleBatchEvaluatorSelect}
/>
@ -462,6 +442,8 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
<SupplierEvaluatorModal
visible={evaluatorModalVisible}
onCancel={() => setEvaluatorModalVisible(false)}
filter={mode === 'division'}
filterUserIds={filterUserIds}
onSelect={handleEvaluatorSelect}
currentSupplier={currentSupplier}
mode={modalMode}

View File

@ -36,17 +36,7 @@ const SupplierSelectStepComponent = (props: SupplierSelectStepProps) => {
// 这里可以添加自定义验证逻辑
return Promise.resolve();
},
getFieldsValue: () => {
return {
selectedSuppliers,
supplierIds: selectedSuppliers.map((supplier: SupplierItem) => ({ id: supplier.id }))
};
},
setFieldsValue: (values: any) => {
if (values.selectedSuppliers) {
setSelectedSuppliers(values.selectedSuppliers);
}
},
// 删除不必要的方法因为现在使用Dva管理数据
}));
// 处理供应商选择

View File

@ -1,32 +1,13 @@
import React, { useState, useEffect } from 'react';
import {
Button,
Table,
Space,
Modal,
message,
Input,
Select,
Form,
Tooltip,
Tag,
TablePaginationConfig,
DatePicker,
Row,
Col,
} from 'antd';
import {
PlusOutlined,
DeleteOutlined,
ExclamationCircleOutlined,
SearchOutlined,
EditOutlined,
EyeOutlined,
} from '@ant-design/icons';
import { Button, Table, Space, message, Input, Select, Form, Tooltip, Tag, DatePicker } from 'antd';
import type { TablePaginationConfig } from 'antd/es/table';
import { PlusOutlined, DeleteOutlined, SearchOutlined } from '@ant-design/icons';
import { history } from 'umi';
import { TaskStatus, TaskType, TaskStatusText, TaskStatusColor, TaskTypeText } from '@/dicts/supplierTaskDict';
import { TaskStatus, TaskStatusText, TaskStatusColor } from '@/dicts/supplierTaskDict';
import { getTaskList } from '@/servers/api/supplierEvaluate';
import styles from './supplierTaskManage.less';
import type { TaskRequest, TaskRecord, TaskItem } from '@/servers/dao/supplierEvaluateTask';
import type { TaskSearchParams } from '@/servers/dao/supplierEvaluateTask';
const { Option } = Select;
const { RangePicker } = DatePicker;
@ -34,7 +15,7 @@ const { RangePicker } = DatePicker;
const SupplierTaskManage: React.FC = () => {
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
const [taskData, setTaskData] = useState<SupplierEvaluate.TaskRecord[]>([]);
const [taskData, setTaskData] = useState<TaskItem[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10,
@ -43,13 +24,18 @@ const SupplierTaskManage: React.FC = () => {
showQuickJumper: true,
showTotal: (total) => `${total} 条记录`,
});
const [searchParams, setSearchParams] = useState<SupplierEvaluate.TaskSearchParams>({});
const [searchParams, setSearchParams] = useState<TaskSearchParams>({
basePageRequest: {
pageNo: 1,
pageSize: 10,
},
});
// 获取任务列表
const fetchTaskList = async (
current = 1,
pageSize = 10,
params: SupplierEvaluate.TaskSearchParams = searchParams,
params: TaskSearchParams = searchParams,
) => {
// 更新搜索参数状态
if (params !== searchParams) {
@ -59,7 +45,7 @@ const SupplierTaskManage: React.FC = () => {
setLoading(true);
try {
// 构造请求参数
const requestParams: SupplierEvaluate.TaskRequest = {
const requestParams: TaskSearchParams = {
basePageRequest: {
pageNo: current,
pageSize: pageSize,
@ -83,24 +69,7 @@ const SupplierTaskManage: React.FC = () => {
if (response.success) {
// 处理返回的数据
const { records, total, current: currentPage, size } = response.data;
// 转换数据结构以适应组件
const formattedData = records.map(item => ({
id: item.id || '',
key: item.id || '',
taskName: item.evaluateTheme || '',
taskCode: item.id || '', // 使用id作为临时的taskCode
status: item.status || '',
startTime: item.startTime || '',
endTime: item.endTime || '',
createBy: item.tenantName || '',
// 添加必要的字段以符合TaskRecord类型
taskType: TaskType.REGULAR, // 默认值实际应从API获取
templateName: '评价模板', // 默认值实际应从API获取
createTime: item.startTime || '', // 使用开始时间作为创建时间
}));
setTaskData(formattedData);
setTaskData(records);
setPagination({
...pagination,
current: currentPage,
@ -120,21 +89,26 @@ const SupplierTaskManage: React.FC = () => {
// 首次加载获取数据
useEffect(() => {
fetchTaskList(pagination.current, pagination.pageSize, {});
fetchTaskList(pagination.current, pagination.pageSize, searchParams);
}, []);
// 处理查看
const handleView = (record: SupplierEvaluate.TaskRecord) => {
const handleView = (record: TaskItem) => {
// 跳转到详情页面
history.push(`supplierTaskManageDetail?id=${record.id}`);
};
// 处理编辑
const handleEdit = (record: SupplierEvaluate.TaskRecord) => {
const handleEdit = (record: TaskItem) => {
// 跳转到编辑页面(复用新增页面)
history.push(`supplierTaskManageAdd?id=${record.id}&mode=edit`);
};
// 处理分工
const handleDivision = (record: TaskItem) => {
// 跳转到分工页面
history.push(`supplierTaskManageAdd?id=${record.id}&mode=division`);
};
// 获取状态标签
const getStatusTag = (status: string) => {
@ -151,28 +125,28 @@ const SupplierTaskManage: React.FC = () => {
const columns = [
{
title: '序号',
render: (_: any, __: SupplierEvaluate.TaskRecord, index: number) =>
render: (_: any, __: TaskItem, index: number) =>
(pagination.current! - 1) * pagination.pageSize! + index + 1,
width: 80,
},
{
title: '评价主题',
dataIndex: 'taskName',
key: 'taskName',
dataIndex: 'evaluateTheme',
key: 'evaluateTheme',
width: 200,
ellipsis: {
showTitle: false,
},
render: (taskName: string) => (
<Tooltip placement="topLeft" title={taskName}>
{taskName}
render: (evaluateTheme: string) => (
<Tooltip placement="topLeft" title={evaluateTheme}>
{evaluateTheme}
</Tooltip>
),
},
{
title: '发起单位',
dataIndex: 'createBy',
key: 'createBy',
dataIndex: 'tenantName',
key: 'tenantName',
width: 150,
},
{
@ -199,11 +173,17 @@ const SupplierTaskManage: React.FC = () => {
key: 'action',
width: 150,
align: 'center' as const,
render: (_: unknown, record: SupplierEvaluate.TaskRecord) => (
render: (_: unknown, record: TaskItem) => (
<Space size="middle">
<Button type="link" onClick={() => handleView(record)}>
</Button>
{record.division == '1' && (
<Button type="link" onClick={() => handleDivision(record)}>
</Button>
)}
<Button type="link" onClick={() => handleEdit(record)}>
</Button>
@ -227,7 +207,7 @@ const SupplierTaskManage: React.FC = () => {
params.dateRange = [dateRange[0].format('YYYY-MM-DD'), dateRange[1].format('YYYY-MM-DD')];
}
fetchTaskList(1, pagination.pageSize, params);
fetchTaskList(1, pagination.pageSize, searchParams);
};
return (
@ -263,7 +243,13 @@ const SupplierTaskManage: React.FC = () => {
icon={<DeleteOutlined />}
onClick={() => {
form.resetFields();
fetchTaskList(1, pagination.pageSize, {});
setSearchParams({
basePageRequest: {
pageNo: 1,
pageSize: 10,
},
});
fetchTaskList(1, pagination.pageSize, searchParams);
}}
>
@ -280,6 +266,7 @@ const SupplierTaskManage: React.FC = () => {
<div className={styles.contentArea}>
<Table
columns={columns}
rowKey="id"
dataSource={taskData}
pagination={pagination}
loading={loading}

View File

@ -46,6 +46,7 @@ const SupplierTaskManageAdd: React.FC<PageProps> = ({ supplierTaskManage, dispat
// 判断是否为编辑模式
const urlParams = getUrlParams();
const isEditMode = urlParams.mode === 'edit' && urlParams.id;
const isDivisionMode = urlParams.mode === 'division' && urlParams.id;
const taskId = urlParams.id || '';
// 创建表单引用,用于访问子组件的表单方法(主要用于验证)
@ -62,19 +63,50 @@ const SupplierTaskManageAdd: React.FC<PageProps> = ({ supplierTaskManage, dispat
* 利用useEffect在组件挂载或依赖项变化时触发
*/
useEffect(() => {
if (isEditMode && taskId && dispatch) {
if ((isEditMode || isDivisionMode) && taskId && dispatch) {
dispatch({
type: 'supplierTaskManage/saveMode',
payload: 'edit',
});
// 编辑模式,获取任务详情
dispatch({
type: 'supplierTaskManage/fetchTaskDetail',
payload: { taskId },
});
if (isDivisionMode) {
dispatch({
type: 'supplierTaskManage/saveMode',
payload: 'division',
});
dispatch({
type: 'supplierTaskManage/setCurrentStep',
payload: 2,
});
}
} else if (dispatch) {
dispatch({
type: 'supplierTaskManage/setMode',
payload: 'add',
});
// 新建模式,重置状态
dispatch({
type: 'supplierTaskManage/resetState',
});
}
}, [isEditMode, taskId, dispatch]);
}, [isEditMode, isDivisionMode, taskId, dispatch]);
/**
* 组件卸载时重置状态
*/
useEffect(() => {
return () => {
if (dispatch) {
dispatch({
type: 'supplierTaskManage/resetState',
});
}
};
}, [dispatch]);
// 步骤配置,定义每个步骤的标题、描述和内容组件
const steps = [
@ -277,7 +309,8 @@ const SupplierTaskManageAdd: React.FC<PageProps> = ({ supplierTaskManage, dispat
{/* 步骤操作按钮 */}
<div className={styles.stepsAction}>
<Space>
{currentStep > 0 && <Button onClick={handlePrev}></Button>}
{/* 如果当前是评价分工步骤,则不显示上一步按钮 */}
{currentStep > (isDivisionMode ? 2 : 0) && <Button onClick={handlePrev}></Button>}
{currentStep < steps.length - 1 && (
<Button type="primary" onClick={handleNext}>

View File

@ -7,7 +7,7 @@ import type {
TemplateAddRequest,
TemplateUpdateRequest,
CategoryTreeResponse,
TaskRequest,
TaskSearchParams,
TaskResponse,
EvaluateTaskRequest,
EvaluateTaskData,
@ -151,7 +151,7 @@ export async function getDepartmentList() {
* @param params 查询参数
* @returns Promise
*/
export async function getTaskList(params: TaskRequest) {
export async function getTaskList(params: TaskSearchParams) {
return request<TaskResponse>('/coscoEvaluate/task/getPage', {
method: 'POST',
data: params,

View File

@ -29,6 +29,7 @@ declare namespace API {
userDeptId: string;
position?: string;
selected?: boolean;
isSelected?: boolean;
}
export interface Department {

View File

@ -140,6 +140,23 @@ export interface CategoryTreeItem {
/**
* 任务查询请求
*/
// 供应商评价任务记录类型
export interface TaskRecord {
id: string;
taskName: string;
taskCode: string;
taskType: string;
templateName: string;
status: string;
startTime: string;
endTime: string;
createBy: string;
createTime: string;
updateBy?: string;
updateTime?: string;
key?: string;
}
export interface TaskRequest {
current?: number;
pageSize?: number;
@ -150,6 +167,15 @@ export interface TaskRequest {
categoryId?: string;
status?: string;
}
// 供应商评价任务查询参数
export interface TaskSearchParams {
basePageRequest: API.BasePageRequest;
evaluateTheme?: string;
status?: string;
dateRange?: string[];
startTime?: string;
endTime?: string;
}
/**
* 任务查询响应
@ -185,16 +211,7 @@ export interface TaskItem {
createBy: string;
[key: string]: any;
}
/*
人员信息
*/
export interface PersonnelItem {
id: string;
name: string;
position: string;
userDept: string;
userDeptId: string;
}
// 评价结果相关类型
/**
@ -385,16 +402,24 @@ export interface EvaluateRuleUpdateRequest {
/**
* 供应商评价任务详情接口类型定义
*/
export interface IndicatorList {
export interface IndicatorItem {
indicatorIds: string[];
type: number;
userId: string;
}
export interface User {
/*
人员信息
*/
export interface PersonnelItem {
id: string;
name: string;
userId: string;
userName: string;
position: string;
userDept: string;
userDeptId: string;
indicatorIds?: string[];
}
/**
* 任务详情数据
@ -412,7 +437,7 @@ export interface TaskDetailData {
evaluateTheme: string | null;
evaluateYear: string | null;
id: string | null;
indicatorList: IndicatorList[] | null;
indicatorList: IndicatorItem[] | null;
lastUpdateTime: string | null;
startTime: string | null;
status: string;
@ -420,7 +445,7 @@ export interface TaskDetailData {
id: string;
userIds: string[];
}[] | null;
userList: User[];
userList: PersonnelItem[];
suppliers: {
id: string;
supplierName: string;
@ -449,7 +474,7 @@ export interface TaskDetailData {
deptName: string;
supplierId: string;
supplierName: string;
userList: User[];
userList: PersonnelItem[];
}[],
[property: string]: any;
}
@ -475,6 +500,7 @@ export interface TaskDetailResponse {
// 新增评价任务和修改 请求参数定义
export type TaskAddRequest = {
id?: string;
/**
* 品类限制类型0.通用不限品类、1.限制品类)
*/
@ -491,7 +517,7 @@ export type TaskAddRequest = {
* 评价年度
*/
evaluateYear: string;
indicatorList: IndicatorList[];
indicatorList: IndicatorItem[];
/**
* 评价开始时间
*/
@ -508,7 +534,11 @@ export type TaskAddRequest = {
* 是否下级部门可以添加评价信息 0否1是
*/
taskStatus?: TaskNotifyLowerUnits | null;
[property: string]: any;
/*
供应商列表
*/
selectedSuppliers?: SupplierItem[];
userList?: PersonnelItem[];
}
/**
* 供应商项
@ -516,11 +546,13 @@ export type TaskAddRequest = {
export interface SupplierItem {
id: string; // 供应商ID
supplierName: string; // 供应商名称
supplierId?: string; // 供应商ID
socialCreditCode?: string; // 统一社会信用代码
category?: string; // 品类
department?: string; // 准入部门
evaluatorCount: number; // 评价人员数量
evaluators: User[]; // 评价人员列表
evaluatorCount?: number; // 评价人员数量
evaluators: PersonnelItem[]; // 评价人员列表
deptName?: string; // 部门名称
// 其他可能的字段
[key: string]: any;
}

View File

@ -14,6 +14,7 @@ export interface PersonnelItem {
position?: string; // 职位(可选)
selected?: boolean; // 是否被选中用于UI显示
indicatorIds?: string[]; // 指标ID列表
isSelected?: boolean; // 是否被选中用于UI显示
// 其他可能的API字段
}