供应商评价任务管理详情 开发以及对接

This commit is contained in:
linxd
2025-06-25 11:57:17 +08:00
parent e5ec9a46d8
commit 09c67189b5
21 changed files with 904 additions and 302 deletions

View File

@ -103,6 +103,16 @@ export default [
},
component: '@/pages/supplierEvaluateManage/supplierTaskManage/supplierTaskManageAdd',
},
{
name: 'supplierTaskManageDetail',
path: 'supplierTaskManageDetail',
meta: {
title: '任务管理详情',
hide: true,
icon: 'icon-liebiaomoshi',
},
component: '@/pages/supplierEvaluateManage/supplierTaskManage/supplierTaskManageDetail',
},
{
name: 'supplierEvaluateScore',
path: 'supplierEvaluateScore',

View File

@ -77,7 +77,8 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
const personnelData: API.PersonnelItem[] = users.map((user) => ({
id: user.userId, // 用户ID
name: user.userName, // 用户名称
department: user.userDept, // 用户部门
userDept: user.userDept, // 用户部门
userDeptId: user.userDeptId, // 用户部门ID
position: '', // API中没有提供职位信息
}));
@ -138,8 +139,8 @@ const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps
},
{
title: '部门',
dataIndex: 'department',
key: 'department',
dataIndex: 'userDept',
key: 'userDept',
},
];

View File

@ -0,0 +1,45 @@
import React from 'react';
import { Card, Descriptions, Tag } from 'antd';
import { TaskStatusColor, TaskStatusText } from '@/dicts/supplierTaskDict';
import styles from '../../supplierTaskManageDetail.less';
import { CategoryLimitationType, CategoryLimitationTypeText } from '@/dicts/supplierTemplateDict';
interface BasicInfoProps {
taskData: SupplierEvaluate.TaskDetailData;
}
const BasicInfo: React.FC<BasicInfoProps> = ({ taskData }) => {
// 获取状态标签
const getStatusTag = (status: string) => {
const color = TaskStatusColor[status as keyof typeof TaskStatusColor] || 'default';
const text = TaskStatusText[status as keyof typeof TaskStatusText] || '未知状态';
return <Tag color={color}>{text}</Tag>;
};
return (
<Card className={styles.detailCard}>
<Descriptions title="基本信息" bordered column={2}>
<Descriptions.Item label="评价主题">{taskData.evaluateTheme || '--'}</Descriptions.Item>
<Descriptions.Item label="评价状态">
{getStatusTag(taskData.status || '')}
</Descriptions.Item>
<Descriptions.Item label="评价年份">{taskData.evaluateYear || '--'}</Descriptions.Item>
<Descriptions.Item label="开始时间">{taskData.startTime || '--'}</Descriptions.Item>
<Descriptions.Item label="结束时间">{taskData.endTime || '--'}</Descriptions.Item>
<Descriptions.Item label="评价模板">{taskData.templateName || '--'}</Descriptions.Item>
<Descriptions.Item label="品类限制">
{
CategoryLimitationTypeText[
taskData.categoryLimitation as keyof typeof CategoryLimitationTypeText
]
}
</Descriptions.Item>
{taskData.categoryId && (
<Descriptions.Item label="品类">{taskData.categoryName}</Descriptions.Item>
)}
</Descriptions>
</Card>
);
};
export default BasicInfo;

View File

@ -0,0 +1,88 @@
import React from 'react';
import { Card, Table, Button, message } from 'antd';
import { UnorderedListOutlined } from '@ant-design/icons';
import styles from '../../supplierTaskManageDetail.less';
import type { TaskDetailData, IndicatorList, User } from '@/servers/types/supplierEvaluateTask';
interface EvaluatorInfoProps {
taskData: TaskDetailData;
onViewIndicators: (record: IndicatorList) => void;
}
const EvaluatorInfo: React.FC<EvaluatorInfoProps> = ({ taskData, onViewIndicators }) => {
const userList = taskData.userList;
// 查看评价人员分工
const handleViewIndicators = (record: IndicatorList) => {
if (record.indicatorIds && record.indicatorIds.length > 0) {
onViewIndicators(record);
} else {
message.info('该评价人员没有分配指标');
}
};
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
render: (_: any, __: any, index: number) => index + 1,
width: 80,
},
{
title: '评价人员',
dataIndex: 'userId',
key: 'userId',
render: (userId: string) => {
try {
const user = userList.find((userItem: User) => userItem.userId === userId);
return user?.userName;
} catch (error) {
console.error('获取评价人员信息失败:', error);
return userId;
}
},
},
{
title: '评价类型',
dataIndex: 'type',
key: 'type',
render: (type: string) => (type === '1' ? '按指标评价' : '按评价单评价'),
},
{
title: '指标数量',
dataIndex: 'indicatorIds',
key: 'indicatorCount',
render: (indicatorIds: string[]) => indicatorIds?.length || 0,
},
{
title: '操作',
key: 'action',
render: (record: any) => (
<Button
type="link"
onClick={() => handleViewIndicators(record)}
>
</Button>
),
},
];
if (!taskData || !taskData.indicatorList || taskData.indicatorList.length === 0) {
return <div className={styles.emptyData}></div>;
}
return (
<Card className={styles.detailCard}>
<Table
columns={columns}
dataSource={taskData.indicatorList}
rowKey="userId"
pagination={false}
className={styles.tableContainer}
/>
</Card>
);
};
export default EvaluatorInfo;

View File

@ -0,0 +1,42 @@
import React from 'react';
import { Modal, Button, Tag } from 'antd';
import styles from '../../supplierTaskManageDetail.less';
import type {TaskDetailData} from '@/servers/types/supplierEvaluateTask'
interface EvaluatorModalProps {
visible: boolean;
supplier: TaskDetailData;
onCancel: () => void;
}
const EvaluatorModal: React.FC<EvaluatorModalProps> = ({ visible, supplier, onCancel }) => {
return (
<Modal
title={`${supplier?.supplierName || ''}的评价人员`}
visible={visible}
onCancel={onCancel}
footer={[
<Button key="close" onClick={onCancel}>
</Button>
]}
width={600}
>
{supplier?.userList?.length > 0 ? (
<div className={styles.evaluatorModalContent}>
<div className={styles.evaluatorList}>
{supplier.userList.map((user) => (
<Tag key={user.userId} className={styles.evaluatorTag}>
{user.userDept} - {user.userName}
</Tag>
))}
</div>
</div>
) : (
<div className={styles.emptyData}></div>
)}
</Modal>
);
};
export default EvaluatorModal;

View File

@ -0,0 +1,99 @@
import React, { useState, useEffect } from 'react';
import { Modal, Button, Spin } from 'antd';
import styles from '../../supplierTaskManageDetail.less';
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable/EvaluateTemplateTable';
import { getTemplateDetail } from '@/servers/api/supplierEvaluate';
interface IndicatorModalProps {
visible: boolean;
evaluatorId: string;
indicators: string[];
templateId?: string;
onCancel: () => void;
}
const IndicatorModal: React.FC<IndicatorModalProps> = ({
visible,
evaluatorId,
indicators,
templateId,
onCancel
}) => {
const [loading, setLoading] = useState<boolean>(false);
const [filteredIndicators, setFilteredIndicators] = useState<any[]>([]);
// 获取模板详情数据
useEffect(() => {
const fetchTemplateData = async () => {
if (visible && templateId) {
setLoading(true);
try {
const res = await getTemplateDetail(templateId);
if (res.success && res.data) {
// 筛选出当前评价人员负责的指标
if (res.data.indicatorStList && indicators.length > 0) {
// 扁平化处理模板数据,提取出所有二级指标
const allIndicators = [];
for (const stItem of res.data.indicatorStList) {
if (stItem.indicatorNdList) {
for (const ndItem of stItem.indicatorNdList) {
if (indicators.includes(ndItem.id as string)) {
allIndicators.push({
...ndItem,
baseIndicator: stItem.baseIndicator,
descIndicator: stItem.descIndicator,
stScore: stItem.score,
indicatorType: stItem.indicatorType,
id: ndItem.id,
score: ndItem.score,
});
}
}
}
}
setFilteredIndicators(allIndicators);
}
}
} catch (error) {
console.error('获取模板详情失败:', error);
} finally {
setLoading(false);
}
}
};
fetchTemplateData();
}, [visible, templateId, indicators]);
return (
<Modal
title={`评价人员 ${evaluatorId} 的指标分工`}
visible={visible}
onCancel={onCancel}
footer={[
<Button key="close" onClick={onCancel}>
</Button>
]}
width={1200} // 增加宽度以适应表格
>
{loading ? (
<div className={styles.loadingContainer}>
<Spin tip="加载中..." />
</div>
) : indicators.length > 0 && filteredIndicators.length > 0 ? (
<div className={styles.indicatorModalContent}>
<EvaluateTemplateTable
value={filteredIndicators}
isDetail={true}
/>
</div>
) : (
<div className={styles.emptyData}></div>
)}
</Modal>
);
};
export default IndicatorModal;

View File

@ -0,0 +1,95 @@
import React from 'react';
import { Card, Table, Button, message } from 'antd';
import { TeamOutlined } from '@ant-design/icons';
import styles from '../../supplierTaskManageDetail.less';
import type { TaskDetailData,User } from '@/servers/types/supplierEvaluateTask';
interface SupplierInfoProps {
taskData: TaskDetailData;
onViewEvaluators: (supplier: any) => void;
}
const SupplierInfo: React.FC<SupplierInfoProps> = ({ taskData, onViewEvaluators }) => {
// 查看供应商评价人员
const handleViewSupplierEvaluators = (record: TaskDetailData) => {
if (!taskData || !taskData.supplierIds) {
message.error('无法获取供应商评价人员信息');
return;
}
// 根据供应商ID查找对应的userIds
const supplierData = taskData.supplierIds.find((item) => item.id === record.supplierId);
let userList: User[] = [];
try {
userList = taskData.userList.filter((item) => supplierData?.userIds.includes(item.userId));
} catch (error) {
console.error('获取供应商评价人员信息失败:', error);
}
if (supplierData) {
onViewEvaluators({
...record,
userIds: supplierData.userIds,
userList: userList,
});
} else {
message.error('未找到该供应商的评价人员信息');
}
};
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
render: (_: any, __: any, index: number) => index + 1,
width: 80,
},
{
title: '供应商名称',
dataIndex: 'supplierName',
key: 'supplierName',
},
{
title: '部门',
dataIndex: 'deptName',
key: 'deptName',
},
{
title: '品类',
dataIndex: 'categoryName',
key: 'categoryName',
render: (text: string) => text || '--',
},
{
title: '操作',
key: 'action',
render: (record: any) => (
<Button
type="link"
onClick={() => handleViewSupplierEvaluators(record)}
>
</Button>
),
},
];
if (!taskData || !taskData.blackSupplierVos || taskData.blackSupplierVos.length === 0) {
return <div className={styles.emptyData}></div>;
}
return (
<Card className={styles.detailCard}>
<Table
columns={columns}
dataSource={taskData.blackSupplierVos}
rowKey="supplierId"
pagination={false}
className={styles.tableContainer}
/>
</Card>
);
};
export default SupplierInfo;

View File

@ -0,0 +1,48 @@
import React from 'react';
import { Card, Table } from 'antd';
import styles from '../../supplierTaskManageDetail.less';
interface WeightInfoProps {
taskData: SupplierEvaluate.TaskDetailData;
}
const WeightInfo: React.FC<WeightInfoProps> = ({ taskData }) => {
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
render: (_: any, __: any, index: number) => index + 1,
width: 80,
},
{
title: '部门名称',
dataIndex: 'weightDept',
key: 'weightDept',
},
{
title: '权重值',
dataIndex: 'weightValue',
key: 'weightValue',
render: (value: number) => `${value}%`,
},
];
if (!taskData || !taskData.taskDeptWeightList || taskData.taskDeptWeightList.length === 0) {
return <div className={styles.emptyData}></div>;
}
return (
<Card className={styles.detailCard}>
<Table
columns={columns}
dataSource={taskData.taskDeptWeightList}
rowKey="id"
pagination={false}
className={styles.tableContainer}
/>
</Card>
);
};
export default WeightInfo;

View File

@ -0,0 +1,15 @@
import BasicInfo from './BasicInfo';
import SupplierInfo from './SupplierInfo';
import EvaluatorInfo from './EvaluatorInfo';
import WeightInfo from './WeightInfo';
import EvaluatorModal from './EvaluatorModal';
import IndicatorModal from './IndicatorModal';
export {
BasicInfo,
SupplierInfo,
EvaluatorInfo,
WeightInfo,
EvaluatorModal,
IndicatorModal
};

View File

@ -500,6 +500,7 @@ const DivisionStep = forwardRef<any, DivisionStepProps>(({ formData, onFormDataC
title="设置评价指标分工"
visible={templateViewModalVisible}
onCancel={handleCloseTemplateViewModal}
width={1200}
footer={[
<Button key="cancel" onClick={handleCloseTemplateViewModal}>

View File

@ -89,7 +89,6 @@ const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(
},
setFieldsValue: (values: any) => {
if (values.suppliersWithEvaluators) {
debugger;
setSuppliers(values.suppliersWithEvaluators);
}
if (values.weightUnits) {
@ -107,7 +106,7 @@ const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(
const evaluators = supplier.evaluators || [];
return {
...supplier,
department: supplier.userDept || '采购部', // 假设部门数据,实际应该从上一步获取
userDept: supplier.userDept || '采购部', // 假设部门数据,实际应该从上一步获取
evaluatorCount: evaluators.length,
evaluators: evaluators,
};
@ -130,36 +129,42 @@ const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(
// 当选择的人员变化时,更新权重单位列表
useEffect(() => {
// 抽取所有评价人员的部门
const allDepartments: string[] = [];
const allDepartments: PersonnelItem[] = [];
suppliers.forEach((supplier) => {
if (supplier.evaluators && supplier.evaluators.length > 0) {
supplier.evaluators.forEach((evaluator) => {
if (evaluator.department) {
allDepartments.push(evaluator.department);
if (evaluator.userDept) {
allDepartments.push(evaluator);
}
});
}
});
// 去重部门列表
const uniqueDepartments = [...new Set(allDepartments)];
// 去重部门列表 - 根据部门ID去重
const departmentMap = new Map<string, PersonnelItem>();
allDepartments.forEach(dept => {
if (dept.userDeptId && !departmentMap.has(dept.userDeptId)) {
departmentMap.set(dept.userDeptId, dept);
}
});
const uniqueDepartments = Array.from(departmentMap.values());
// 如果有部门数据,生成权重单位列表
if (uniqueDepartments.length > 0) {
const newWeightUnits: WeightUnit[] = uniqueDepartments.map((dept, index) => ({
id: (index + 1).toString(),
name: dept,
id: dept.userDeptId,
name: dept.userDept,
weight: 0, // 默认权重为0
}));
// 更新权重单位列表,保留原有权重值
setWeightUnits((prevUnits) => {
const prevUnitsMap = new Map(prevUnits.map((unit) => [unit.name, unit.weight]));
const prevUnitsMap = new Map(prevUnits.map((unit) => [unit.id, unit.weight]));
return newWeightUnits.map((unit) => ({
...unit,
weight: prevUnitsMap.get(unit.name) || 0, // 如果有原来的权重值则保留
weight: prevUnitsMap.get(unit.id) || 0, // 如果有原来的权重值则保留
}));
});
}
@ -220,7 +225,16 @@ const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(
setWeightUnits(updatedWeightUnits);
// 将更新后的权重数据传递给父组件
updateFormData({ weightUnits: updatedWeightUnits });
// 同时转换为taskDeptWeightList格式
const taskDeptWeightList = updatedWeightUnits.map(unit => ({
weightDept: unit.name, // 使用部门名称
weightValue: unit.weight.toString(), // 转换为字符串格式
}));
updateFormData({
weightUnits: updatedWeightUnits,
taskDeptWeightList: taskDeptWeightList,
});
setWeightSettingModalVisible(false);
});
@ -235,7 +249,6 @@ const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(
// 处理查看评价人员
const handleViewEvaluators = (supplier: SupplierItem) => {
// 查找完整的供应商数据包括evaluators
const fullSupplier = suppliers.find((s) => s.id === supplier.id);
if (fullSupplier) {

View File

@ -25,7 +25,7 @@ import {
} from '@ant-design/icons';
import { history } from 'umi';
import { TaskStatus, TaskType, TaskStatusText, TaskStatusColor, TaskTypeText } from '@/dicts/supplierTaskDict';
import { getTaskList, deleteTask } from '@/servers/api/supplierEvaluate';
import { getTaskList } from '@/servers/api/supplierEvaluate';
import styles from './supplierTaskManage.less';
const { Option } = Select;
@ -34,13 +34,6 @@ const { RangePicker } = DatePicker;
const SupplierTaskManage: React.FC = () => {
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [isEdit, setIsEdit] = useState<boolean>(false);
const [isViewMode, setIsViewMode] = useState<boolean>(false);
const [currentId, setCurrentId] = useState<string>('');
// 查看详情数据
const [viewData, setViewData] = useState<SupplierEvaluate.TaskRecord | null>(null);
const [taskData, setTaskData] = useState<SupplierEvaluate.TaskRecord[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
@ -132,72 +125,16 @@ const SupplierTaskManage: React.FC = () => {
// 处理查看
const handleView = (record: SupplierEvaluate.TaskRecord) => {
setCurrentId(record.id);
setIsViewMode(true);
setViewData(record);
setModalVisible(true);
// 跳转到详情页面
history.push(`supplierTaskManageDetail?id=${record.id}`);
};
// 处理编辑
const handleEdit = (record: SupplierEvaluate.TaskRecord) => {
setIsEdit(true);
setIsViewMode(false);
setCurrentId(record.id);
setViewData(record);
setModalVisible(true);
// 跳转到编辑页面(复用新增页面)
history.push(`supplierTaskManageAdd?id=${record.id}&mode=edit`);
};
// 处理删除
const showDeleteConfirm = (record: SupplierEvaluate.TaskRecord) => {
Modal.confirm({
title: '确认删除',
icon: <ExclamationCircleOutlined />,
content: `确定要删除任务: ${record.taskName}?`,
okText: '确定',
okType: 'danger',
cancelText: '取消',
maskClosable: false,
onOk: async () => {
try {
const response = await deleteTask(record.id);
if (response.success) {
message.success('删除成功');
fetchTaskList(pagination.current, pagination.pageSize, searchParams);
} else {
message.error(response.message || '删除任务失败');
}
} catch (error) {
console.error('删除任务失败:', error);
message.error('删除任务失败');
}
},
});
};
// 处理发布/取消
const handlePublishStatus = (record: SupplierEvaluate.TaskRecord) => {
const isInProgress = record.status === TaskStatus.PROCESSING;
const actionText = isInProgress ? '取消' : '开始';
Modal.confirm({
title: `确认${actionText}`,
icon: <ExclamationCircleOutlined />,
content: `确定要${actionText}任务: ${record.taskName}?`,
okText: '确定',
cancelText: '取消',
maskClosable: false,
onOk: async () => {
try {
// 这里需要添加实际的API调用
message.success(`${actionText}成功`);
fetchTaskList(pagination.current, pagination.pageSize, searchParams);
} catch (error) {
console.error(`${actionText}失败:`, error);
message.error(`${actionText}失败`);
}
},
});
};
// 获取状态标签
const getStatusTag = (status: string) => {
@ -260,7 +197,7 @@ const SupplierTaskManage: React.FC = () => {
{
title: '操作',
key: 'action',
width: 180,
width: 150,
align: 'center' as const,
render: (_: unknown, record: SupplierEvaluate.TaskRecord) => (
<Space size="middle">
@ -270,9 +207,6 @@ const SupplierTaskManage: React.FC = () => {
<Button type="link" onClick={() => handleEdit(record)}>
</Button>
<Button type="link" onClick={() => showDeleteConfirm(record)}>
</Button>
</Space>
),
},
@ -296,164 +230,6 @@ const SupplierTaskManage: React.FC = () => {
fetchTaskList(1, pagination.pageSize, params);
};
// 处理模态框取消
const handleModalCancel = () => {
setModalVisible(false);
setIsViewMode(false);
setViewData(null);
};
// 渲染任务详情
const renderTaskDetail = () => {
if (!viewData) return null;
return (
<div className={styles.taskDetail}>
<Row gutter={[16, 16]}>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.taskName}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.taskCode}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>
{TaskTypeText[viewData.taskType as keyof typeof TaskTypeText] || '未知类型'}
</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}>使</span>
<span className={styles.content}>{viewData.templateName}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{getStatusTag(viewData.status)}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.startTime}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.endTime}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.createBy}</span>
</div>
</Col>
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.createTime}</span>
</div>
</Col>
{viewData.updateBy && (
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.updateBy}</span>
</div>
</Col>
)}
{viewData.updateTime && (
<Col span={12}>
<div className={styles.detailItem}>
<span className={styles.label}></span>
<span className={styles.content}>{viewData.updateTime}</span>
</div>
</Col>
)}
</Row>
</div>
);
};
// 渲染任务表单
const renderTaskForm = () => {
return (
<Form
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
initialValues={viewData || {}}
>
<Form.Item
label="任务名称"
name="taskName"
rules={[{ required: true, message: '请输入任务名称' }]}
>
<Input placeholder="请输入任务名称" />
</Form.Item>
<Form.Item
label="任务编号"
name="taskCode"
rules={[{ required: true, message: '请输入任务编号' }]}
>
<Input placeholder="请输入任务编号" disabled={isEdit} />
</Form.Item>
<Form.Item
label="任务类型"
name="taskType"
rules={[{ required: true, message: '请选择任务类型' }]}
>
<Select placeholder="请选择任务类型">
<Option value={TaskType.REGULAR}>{TaskTypeText[TaskType.REGULAR]}</Option>
<Option value={TaskType.SPECIAL}>{TaskTypeText[TaskType.SPECIAL]}</Option>
</Select>
</Form.Item>
<Form.Item
label="使用模板"
name="templateName"
rules={[{ required: true, message: '请选择使用模板' }]}
>
<Select placeholder="请选择使用模板">
<Option value="常规评价模板1">1</Option>
<Option value="常规评价模板2">2</Option>
<Option value="专项评价模板1">1</Option>
<Option value="专项评价模板2">2</Option>
</Select>
</Form.Item>
<Form.Item
label="时间范围"
rules={[{ required: true, message: '请选择时间范围' }]}
>
<RangePicker />
</Form.Item>
<Form.Item wrapperCol={{ offset: 6, span: 16 }}>
<Button type="primary" htmlType="submit">
</Button>
<Button style={{ marginLeft: 8 }} onClick={handleModalCancel}>
</Button>
</Form.Item>
</Form>
);
};
return (
<div className={`${styles.supplierTaskManageContainer} common-container`}>
<div className={styles.filterActionRow}>
@ -511,31 +287,6 @@ const SupplierTaskManage: React.FC = () => {
scroll={{ x: 1500 }}
/>
</div>
{/* 新增/编辑/查看模态框 */}
<Modal
title={isViewMode
? "查看任务详情"
: isEdit
? "编辑任务"
: "新增任务"}
visible={modalVisible}
onCancel={handleModalCancel}
width={800}
maskClosable={false}
destroyOnClose
footer={
isViewMode
? [
<Button key="close" onClick={handleModalCancel}>
</Button>,
]
: null
}
>
{isViewMode ? renderTaskDetail() : renderTaskForm()}
</Modal>
</div>
);
};

View File

@ -23,7 +23,6 @@ const SupplierTaskManageAdd: React.FC = () => {
// 处理表单数据变更
const handleFormDataChange = (data: any) => {
console.log(data)
// 第一步:基本信息
if (data) {
setFormData((prev) => ({ ...prev, ...data }));
@ -55,18 +54,14 @@ const SupplierTaskManageAdd: React.FC = () => {
if (data.weightUnits) {
// 将 weightUnits 存储在 formData.WeightUnit 中
setFormData((prev) => ({ ...prev, WeightUnit: data.weightUnits }));
}
// 同时将 weightUnits 转换为 taskDeptWeightList 格式
const taskDeptWeightList = data.weightUnits.map((unit: any) => ({
weightDept: unit.name,
weightValue: unit.weight.toString(),
}));
// 更新 taskDeptWeightList 和 weightStatus
// 处理部门权重列表
if (data.taskDeptWeightList) {
setFormData((prev) => ({
...prev,
taskDeptWeightList,
weightStatus: taskDeptWeightList.length > 0 ? 1 : 0, // 如果有权重设置则为1否则为0
taskDeptWeightList: data.taskDeptWeightList,
// weightStatus: data.weightStatus || 0
}));
}
};
@ -99,11 +94,6 @@ const SupplierTaskManageAdd: React.FC = () => {
description: '不设置按默认全部指标评价',
content: <DivisionStep formData={formData} onFormDataChange={handleFormDataChange} ref={divisionFormRef} />,
},
{
title: '创建成功',
description: '评价任务创建成功',
content: <div></div>,
},
];
// 处理返回
@ -160,6 +150,7 @@ const SupplierTaskManageAdd: React.FC = () => {
const result = divisionFormRef.current.validate();
if (!result.valid) {
message.error(result.message);
setLoading(false);
return;
}
}
@ -172,6 +163,7 @@ const SupplierTaskManageAdd: React.FC = () => {
templateId: formData.templateId || '', // 模板ID
categoryLimitation: formData.categoryLimitation || '0', // 品类限制
evaluateYear: formData.evaluateYear || '', // 评价年份
// weightStatus: formData.weightStatus || 0, // 权重状态
// 修复供应商ID列表格式确保包含 userIds 字段
supplierIds: formData.selectedSuppliers?.map((supplier: any) => {
@ -191,9 +183,10 @@ const SupplierTaskManageAdd: React.FC = () => {
indicatorIds: item.indicatorIds || [],
})) || [],
// 部门权重列表过滤掉权重为0的
taskDeptWeightList: formData.taskDeptWeightList?.filter((item: any) => {
return item.weightValue !== '0'
}) || [], // 部门权重列表 过滤掉权重为0的
return item.weightValue && item.weightValue !== '0';
}) || [],
};
// 调用API提交数据
@ -201,8 +194,8 @@ const SupplierTaskManageAdd: React.FC = () => {
if (response.success) {
message.success('任务创建成功');
// 显示最后一步(创建成功)
setCurrentStep(steps.length - 1);
// 创建成功后直接返回列表页面
history.push('/supplier/supplierTaskManage');
} else {
message.error(response.message || '提交失败');
}
@ -239,15 +232,15 @@ const SupplierTaskManageAdd: React.FC = () => {
<div className={styles.stepsAction}>
<Space>
{currentStep > 0 && currentStep < steps.length - 1 && (
{currentStep > 0 && (
<Button onClick={handlePrev}></Button>
)}
{currentStep < steps.length - 2 && (
{currentStep < steps.length - 1 && (
<Button type="primary" onClick={handleNext}>
</Button>
)}
{currentStep === steps.length - 2 && (
{currentStep === steps.length - 1 && (
<Button
type="primary"
loading={loading}
@ -257,11 +250,6 @@ const SupplierTaskManageAdd: React.FC = () => {
</Button>
)}
{currentStep === steps.length - 1 && (
<Button type="primary" onClick={handleBack}>
</Button>
)}
</Space>
</div>
</Col>

View File

@ -0,0 +1,100 @@
.loadingContainer {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
}
.detailCard {
margin-bottom: 24px;
}
.supplierList {
display: flex;
flex-direction: column;
gap: 16px;
}
.supplierCard {
margin-bottom: 16px;
}
.indicatorList {
.indicatorItem {
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
&:last-child {
border-bottom: none;
}
}
.indicatorIndex {
width: 30px;
font-weight: bold;
}
.indicatorId {
flex: 1;
}
}
.infoItem {
margin-bottom: 8px;
display: flex;
align-items: flex-start;
}
.label {
font-weight: 500;
margin-right: 8px;
min-width: 100px;
}
.evaluatorList {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.evaluatorTag {
margin-bottom: 8px;
}
.idList {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.emptyData {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
}
.tableContainer {
margin-top: 16px;
}
.weightStatusInfo {
margin-bottom: 16px;
font-size: 14px;
.label {
font-weight: bold;
margin-right: 8px;
}
}
.evaluatorModalContent,
.indicatorModalContent {
max-height: 400px;
overflow-y: auto;
padding: 8px;
}

View File

@ -0,0 +1,154 @@
import React, { useState, useEffect } from 'react';
import { Card, Button, message, Spin, Tabs, Typography } from 'antd';
import { history, useLocation } from 'umi';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { getTaskDetail } from '@/servers/api/supplierEvaluate';
import {
BasicInfo,
SupplierInfo,
EvaluatorInfo,
WeightInfo,
EvaluatorModal,
IndicatorModal
} from './components/Detail';
import styles from './supplierTaskManageDetail.less';
import type { TaskDetailData } from '@/servers/types/supplierEvaluateTask';
const { TabPane } = Tabs;
const { Title } = Typography;
// 解析查询参数
const useQuery = () => {
const { search } = useLocation();
return React.useMemo(() => new URLSearchParams(search), [search]);
};
const SupplierTaskManageDetail: React.FC = () => {
const query = useQuery();
const taskId = query.get('id');
// 数据加载状态
const [loading, setLoading] = useState<boolean>(true);
// 任务数据
const [taskData, setTaskData] = useState<TaskDetailData | null>(null);
// 当前活动标签页
const [activeTab, setActiveTab] = useState<string>('1');
// 模态框状态
const [evaluatorModalVisible, setEvaluatorModalVisible] = useState<boolean>(false);
const [indicatorModalVisible, setIndicatorModalVisible] = useState<boolean>(false);
const [currentSupplier, setCurrentSupplier] = useState<any>(null);
const [currentIndicators, setCurrentIndicators] = useState<string[]>([]);
const [currentEvaluator, setCurrentEvaluator] = useState<string>('');
// 获取任务详情
const fetchTaskDetail = async (id: string) => {
if (!id) {
message.error('任务ID不能为空');
return;
}
setLoading(true);
try {
const response = await getTaskDetail(id);
if (response.success) {
setTaskData(response.data);
} else {
message.error(response.message || '获取任务详情失败');
}
} catch (error) {
console.error('获取任务详情失败:', error);
message.error('获取任务详情失败');
} finally {
setLoading(false);
}
};
// 当组件挂载时,获取任务详情
useEffect(() => {
if (taskId) {
fetchTaskDetail(taskId);
} else {
message.error('未提供任务ID');
history.push('/supplier/supplierTaskManage');
}
}, [taskId]);
// 处理返回
const handleBack = () => {
history.goBack();
};
// 处理查看供应商评价人员
const handleViewSupplierEvaluators = (supplier: any) => {
setCurrentSupplier(supplier);
setEvaluatorModalVisible(true);
};
// 处理查看评价人员分工
const handleViewIndicators = (record: any) => {
setCurrentIndicators(record.indicatorIds || []);
setCurrentEvaluator(record.userId);
setIndicatorModalVisible(true);
};
return (
<div className="common-container">
<Card bordered={false}>
<div className="page-header">
<Title level={4}></Title>
<Button type="link" icon={<ArrowLeftOutlined />} onClick={handleBack}>
</Button>
</div>
{loading ? (
<div className={styles.loadingContainer}>
<Spin size="large" tip="数据加载中..." />
</div>
) : (
<Tabs activeKey={activeTab} onChange={setActiveTab}>
<TabPane tab="基本信息" key="1">
{taskData && <BasicInfo taskData={taskData} />}
</TabPane>
<TabPane tab="供应商信息" key="2">
{taskData && <SupplierInfo
taskData={taskData}
onViewEvaluators={handleViewSupplierEvaluators}
/>}
</TabPane>
<TabPane tab="评价指标分工" key="3">
{taskData && <EvaluatorInfo
taskData={taskData}
onViewIndicators={handleViewIndicators}
/>}
</TabPane>
<TabPane tab="评分单位权重" key="4">
{taskData && <WeightInfo taskData={taskData} />}
</TabPane>
</Tabs>
)}
</Card>
{/* 供应商评价人员模态框 */}
<EvaluatorModal
visible={evaluatorModalVisible}
supplier={currentSupplier}
onCancel={() => setEvaluatorModalVisible(false)}
/>
{/* 评价人员分工模态框 */}
<IndicatorModal
visible={indicatorModalVisible}
evaluatorId={currentEvaluator}
indicators={currentIndicators}
templateId={taskData?.templateId || ''}
onCancel={() => setIndicatorModalVisible(false)}
/>
</div>
);
};
export default SupplierTaskManageDetail;

View File

@ -1,4 +1,5 @@
import request from '@/utils/request';
import type { TaskDetailResponse } from '@/servers/types/supplierEvaluateTask';
/**
* 获取所有模板列表
@ -142,7 +143,7 @@ export async function getTaskList(params: SupplierEvaluate.TaskRequest) {
* @returns Promise
*/
export async function getTaskDetail(id: string) {
return request<API.APIResponse<SupplierEvaluate.TaskRecord>>(`/coscoEvaluate/task/${id}`, {
return request<TaskDetailResponse>(`/coscoEvaluate/task/${id}`, {
method: 'GET',
});
}

View File

@ -25,7 +25,8 @@ declare namespace API {
export interface PersonnelItem {
id: string;
name: string;
department: string;
userDept: string;
userDeptId: string;
position?: string;
selected?: boolean;
}

View File

@ -9,7 +9,8 @@
export interface PersonnelItem {
id: string; // 人员ID
name: string; // 人员姓名
department: string; // 所属部门
userDept: string; // 所属部门
userDeptId: string; // 所属部门ID
position?: string; // 职位(可选)
selected?: boolean; // 是否被选中用于UI显示
// 其他可能的API字段

View File

@ -3,3 +3,4 @@
*/
export * from './evaluator';
export * from './supplierEvaluateTask';

View File

@ -0,0 +1,79 @@
/**
* 供应商评价任务详情接口类型定义
*/
export interface IndicatorList {
indicatorIds: string[];
type: number;
userId: string;
}
export interface User{
userId: string;
userName: string;
userDept: string;
userDeptId: string;
}
/**
* 任务详情数据
*/
export interface TaskDetailData {
categoryId: string | null;
categoryLimitation: string | null;
createBy: string | null;
createDate: string | null;
createTime: string | null;
deleteFlag: string | null;
delFlag: string;
deptId: string | null;
endTime: string | null;
evaluateTheme: string | null;
evaluateYear: string | null;
id: string | null;
indicatorList: IndicatorList[] | null;
lastUpdateTime: string | null;
startTime: string | null;
status: string;
supplierIds: {
id: string;
userIds: string[];
}[] | null;
userList: User[];
suppliers: {
id: string;
supplierName: string;
socialCreditCode?: string;
category?: string;
department?: string;
evaluators: {
id: string;
name: string;
department: string;
position?: string;
}[];
[key: string]: any;
}[] | null;
templateId: string | null;
tenantId: string | null;
tenantName: string | null;
updateBy: string | null;
updateDate: string | null;
updateTime: string | null;
weightDept: string | null;
weightStatus: number | null;
weightValue: string | null;
taskDeptWeightList: {
weightDept: string;
weightValue: string;
}[] | null;
[property: string]: any;
}
/**
* 任务详情响应
*/
export interface TaskDetailResponse {
code: number;
data: TaskDetailData;
message: string;
success: boolean;
[property: string]: any;
}

71
src/typings.d.ts vendored
View File

@ -496,7 +496,7 @@ declare namespace SupplierEvaluate {
/**
* 权重启用状态(0.不启用、1.启用)
*/
weightStatus: number;
// weightStatus: number;
[property: string]: any;
}
@ -508,6 +508,75 @@ declare namespace SupplierEvaluate {
endTime: string;
[property: string]: any;
}
/**
* 任务详情数据
*/
interface TaskDetailData {
categoryId: string | null;
categoryLimitation: string | null;
createBy: string | null;
createDate: string | null;
createTime: string | null;
deleteFlag: string | null;
delFlag: string;
deptId: string | null;
endTime: string | null;
evaluateTheme: string | null;
evaluateYear: string | null;
id: string | null;
indicatorList: {
indicatorIds: string[];
type: number;
userId: string;
}[] | null;
lastUpdateTime: string | null;
startTime: string | null;
status: string;
supplierIds: {
id: string;
userIds: string[];
}[] | null;
suppliers: {
id: string;
supplierName: string;
socialCreditCode?: string;
category?: string;
department?: string;
evaluators: {
id: string;
name: string;
department: string;
position?: string;
}[];
[key: string]: any;
}[] | null;
templateId: string | null;
tenantId: string | null;
tenantName: string | null;
updateBy: string | null;
updateDate: string | null;
updateTime: string | null;
weightDept: string | null;
weightStatus: number | null;
weightValue: string | null;
taskDeptWeightList: {
weightDept: string;
weightValue: string;
}[] | null;
[property: string]: any;
}
/**
* 任务详情响应
*/
interface TaskDetailResponse {
code: number;
data: TaskDetailData;
message: string;
success: boolean;
[property: string]: any;
}
}
declare module '*.css';