年审模块

This commit is contained in:
linxd
2025-06-30 09:43:28 +08:00
parent bf19b53402
commit d775dce037
18 changed files with 118 additions and 1175 deletions

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback, forwardRef, useImperativeHandle } from 'react';
import { Form, Input, Select, DatePicker, Row, Col, Card, Radio } from 'antd';
import moment from 'moment';
import { getAllTemplates } from '@/servers/api/supplierEvaluate';
import { getAllAnnualTemplates } from '@/servers/api/supplierAnnual';
import CategorySelector from '@/components/CategorySelector';
import styles from '../supplierAnnualTaskManageAdd.less';
import { CategoryLimitationType } from '@/dicts/supplierTemplateDict';
@ -43,7 +43,7 @@ const BasicInfoStepComponent = (props: BasicInfoStepProps) => {
const fetchTemplates = async () => {
setLoading(true);
try {
const response = await getAllTemplates();
const response = await getAllAnnualTemplates();
if (response.success && response.data) {
setTemplates(response.data);
}
@ -119,7 +119,7 @@ const BasicInfoStepComponent = (props: BasicInfoStepProps) => {
<Col span={12}>
<Form.Item
label="评价主题"
name="evaluateTheme"
name="annualreviewTheme"
rules={[{ required: true, message: '请输入评价主题' }]}
>
<Input placeholder="请输入" maxLength={50} />
@ -128,7 +128,7 @@ const BasicInfoStepComponent = (props: BasicInfoStepProps) => {
<Col span={12}>
<Form.Item
label="评价年度"
name="evaluateYear"
name="annualreviewYear"
rules={[{ required: true, message: '请选择评价年度' }]}
>
<Select placeholder="请选择年度" style={{ width: '100%' }}>

View File

@ -2,10 +2,10 @@ import React from 'react';
import { Card, Descriptions, Tag } from 'antd';
import { TaskStatusColor, TaskStatusText } from '@/dicts/supplierTaskDict';
import styles from '../../supplierAnnualTaskManageDetail.less';
import { CategoryLimitationType, CategoryLimitationTypeText } from '@/dicts/supplierTemplateDict';
import { CategoryLimitationTypeText } from '@/dicts/supplierTemplateDict';
interface BasicInfoProps {
taskData: SupplierEvaluate.TaskDetailData;
taskData: supplierAnnualTaskManage.TaskDetailData;
}
const BasicInfo: React.FC<BasicInfoProps> = ({ taskData }) => {
@ -19,11 +19,11 @@ const BasicInfo: React.FC<BasicInfoProps> = ({ taskData }) => {
return (
<Card className={styles.detailCard}>
<Descriptions title="基本信息" bordered column={2}>
<Descriptions.Item label="评价主题">{taskData.evaluateTheme || '--'}</Descriptions.Item>
<Descriptions.Item label="评价主题">{taskData.annualreviewTheme || '--'}</Descriptions.Item>
<Descriptions.Item label="评价状态">
{getStatusTag(taskData.status || '')}
</Descriptions.Item>
<Descriptions.Item label="评价年份">{taskData.evaluateYear || '--'}</Descriptions.Item>
<Descriptions.Item label="评价年份">{taskData.annualreviewYear || '--'}</Descriptions.Item>
<Descriptions.Item label="开始时间">{taskData.startTime || '--'}</Descriptions.Item>
<Descriptions.Item label="结束时间">{taskData.endTime || '--'}</Descriptions.Item>
<Descriptions.Item label="评价模板">{taskData.templateName || '--'}</Descriptions.Item>

View File

@ -1,88 +0,0 @@
import React from 'react';
import { Card, Table, Button, message } from 'antd';
import { UnorderedListOutlined } from '@ant-design/icons';
import styles from '../../supplierAnnualTaskManageDetail.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

@ -1,11 +1,10 @@
import React from 'react';
import { Modal, Button, Tag } from 'antd';
import styles from '../../supplierAnnualTaskManageDetail.less';
import type {TaskDetailData} from '@/servers/supplierEvaluateTask'
interface EvaluatorModalProps {
visible: boolean;
supplier: TaskDetailData;
supplier: supplierAnnualTaskManage.TaskDetailData;
onCancel: () => void;
}
@ -27,7 +26,7 @@ const EvaluatorModal: React.FC<EvaluatorModalProps> = ({ visible, supplier, onCa
<div className={styles.evaluatorList}>
{supplier.userList.map((user) => (
<Tag key={user.userId} className={styles.evaluatorTag}>
{user.userDept} - {user.userName}
{user.userDept} - {user.name}
</Tag>
))}
</div>

View File

@ -1,99 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Modal, Button, Spin } from 'antd';
import styles from '../../supplierAnnualTaskManageDetail.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

@ -1,39 +1,22 @@
import React from 'react';
import { Card, Table, Button, message } from 'antd';
import { TeamOutlined } from '@ant-design/icons';
import styles from '../../supplierAnnualTaskManageDetail.less';
import type { TaskDetailData,User } from '@/servers/types/supplierEvaluateTask';
interface SupplierInfoProps {
taskData: TaskDetailData;
taskData: supplierAnnualTaskManage.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) {
const handleViewSupplierEvaluators = (record: supplierAnnualTaskManage.TaskDetailData) => {
if (record.userList && record.userList.length > 0) {
onViewEvaluators({
...record,
userIds: supplierData.userIds,
userList: userList,
userList: record.userList,
});
} else {
message.error('未找到该供应商的评价人员信息');
message.error('未找到该供应商的年审人员信息');
}
};
@ -65,10 +48,7 @@ const SupplierInfo: React.FC<SupplierInfoProps> = ({ taskData, onViewEvaluators
title: '操作',
key: 'action',
render: (record: any) => (
<Button
type="link"
onClick={() => handleViewSupplierEvaluators(record)}
>
<Button type="link" onClick={() => handleViewSupplierEvaluators(record)}>
</Button>
),

View File

@ -1,48 +0,0 @@
import React from 'react';
import { Card, Table } from 'antd';
import styles from '../../supplierAnnualTaskManageDetail.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

@ -1,15 +1,9 @@
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

@ -55,7 +55,7 @@ const SupplierEvaluatorModal: React.FC<SupplierEvaluatorModalProps> = ({
if (!currentSupplier.evaluators || currentSupplier.evaluators.length === 0) {
return (
<div style={{ textAlign: 'center', padding: '20px 0' }}>
&quot;&quot;
&quot;&quot;
</div>
);
}
@ -78,7 +78,7 @@ const SupplierEvaluatorModal: React.FC<SupplierEvaluatorModalProps> = ({
return (
<Modal
title={`${mode === ModalMode.SELECT ? '选择' : '查看'}评价人员 - ${
title={`${mode === ModalMode.SELECT ? '选择' : '查看'}年审人员 - ${
currentSupplier?.supplierName || ''
}`}
visible={visible}

View File

@ -69,9 +69,9 @@ const SupplierTable: React.FC<SupplierTableProps> = ({
key: 'deptName',
},
{
title: '评价人员数',
title: '年审人员数',
align: 'center' as const, // 列对齐方式
dataIndex: 'evaluatorCount', // 评价人员数量字段
dataIndex: 'evaluatorCount', // 年审人员数量字段
key: 'evaluatorCount',
},
{

View File

@ -108,7 +108,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
if (taskFormData.selectedSuppliers && taskFormData.selectedSuppliers.length > 0) {
// 转换上一步的供应商数据,添加评价人员数量字段
const suppliersWithEvaluators = taskFormData.selectedSuppliers.map(
(supplier) => {
(supplier: SupplierItem) => {
// 确保evaluators字段存在且为数组
const evaluators = supplier.evaluators || [];
return {
@ -129,52 +129,6 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
}, [taskFormData]); // 依赖于 taskFormData当 model 数据变化时重新计算
/**
* 当选择的人员变化时,更新权重单位列表
* 根据所有评价人员的部门信息,动态生成权重单位列表
*/
useEffect(() => {
// 从所有供应商的评价人员中提取部门信息
const allDepartments: PersonnelItem[] = [];
suppliers.forEach((supplier) => {
if (supplier.evaluators && supplier.evaluators.length > 0) {
supplier.evaluators.forEach((evaluator) => {
if (evaluator.userDept) {
allDepartments.push(evaluator);
}
});
}
});
// 去重部门列表 - 根据部门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 newTaskDeptWeightList: DeptWeightItem[] = uniqueDepartments.map((dept) => ({
weightDept: dept.userDeptId || '',
weightValue: '0', // 默认权重为0
weightDeptName: dept.userDept || '',
}));
// 更新权重单位列表,保留原有权重值
setTaskDeptWeightList((prevList) => {
const prevValuesMap = new Map(prevList.map((item) => [item.weightDept, item.weightValue]));
return newTaskDeptWeightList.map((item) => ({
...item,
weightValue: prevValuesMap.get(item.weightDept) || '0', // 如果有原来的权重值则保留
}));
});
}
}, [suppliers]); // 依赖于suppliers当选择的供应商或其评价人员变化时重新计算
/**
* 更新表单数据
@ -186,7 +140,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
const { suppliersWithEvaluators }: { suppliersWithEvaluators: SupplierItem[] } = updatedData;
// 构建供应商ID列表
const supplierIds = suppliersWithEvaluators.map((supplier) => ({
id: supplier.id,
suppliedId: supplier.id,
userIds: supplier.evaluators?.map((e: PersonnelItem) => e.id) || [],
}));
@ -223,48 +177,6 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
if (selectedRowKeys.length === 0) return;
setBatchSelectModalVisible(true);
};
/**
* 处理设置评分单位权重按钮点击事件
* 打开权重设置模态框
*/
const handleWeightSetting = () => {
// 将权重数据转换为表单初始值
form.setFieldsValue({
taskDeptWeightList: taskDeptWeightList.reduce((acc, item) => {
acc[item.weightDept] = parseInt(item.weightValue, 10) || 0;
return acc;
}, {} as Record<string, number>),
});
setWeightSettingModalVisible(true);
};
/**
* 保存权重设置
* 更新本地权重数据并同步到 Dva model
*/
const handleSaveWeights = () => {
form.validateFields().then((values) => {
// 将表单值转换回权重列表格式
const updatedTaskDeptWeightList = taskDeptWeightList.map((item) => ({
...item,
weightValue: values.taskDeptWeightList[item.weightDept].toString(),
}));
// 更新本地状态
setTaskDeptWeightList(updatedTaskDeptWeightList);
// 同步到Dva model
updateFormData({
suppliersWithEvaluators: suppliers,
taskDeptWeightList: updatedTaskDeptWeightList,
});
setWeightSettingModalVisible(false);
});
};
/**
* 处理选择评价人员按钮点击事件
* 打开评价人员选择模态框
@ -376,7 +288,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
// 渲染组件
return (
<div className={styles.evaluatorSelectStep}>
<Card title="选择评价人员" bordered={false} className="inner-card">
<Card title="选择年审人员" bordered={false} className="inner-card">
{/* 工具栏区域 */}
{mode !== 'division' && (
<div className={styles.toolbar}>
@ -386,10 +298,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
onClick={handleBatchSelect}
disabled={selectedRowKeys.length === 0}
>
</Button>
<Button onClick={handleWeightSetting} disabled={taskDeptWeightList.length === 0}>
</Button>
</Space>
</div>
@ -412,7 +321,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
/>
)}
{/* 批量选择评价人员弹窗 */}
{/* 批量选择年审人员弹窗 */}
<BatchEvaluatorModal
visible={batchSelectModalVisible}
onCancel={() => setBatchSelectModalVisible(false)}
@ -421,7 +330,7 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
onSelect={handleBatchEvaluatorSelect}
/>
{/* 单个供应商评价人员弹窗 */}
{/* 单个供应商年审人员弹窗 */}
<SupplierEvaluatorModal
visible={evaluatorModalVisible}
onCancel={() => setEvaluatorModalVisible(false)}
@ -432,14 +341,6 @@ const EvaluatorSelectStepComponent = (props: EvaluatorSelectStepProps) => {
mode={modalMode}
/>
{/* 权重设置弹窗 */}
<WeightSettingModal
visible={weightSettingModalVisible}
onCancel={() => setWeightSettingModalVisible(false)}
onOk={handleSaveWeights}
taskDeptWeightList={taskDeptWeightList}
form={form}
/>
</Card>
</div>
);

View File

@ -2,7 +2,7 @@ import React, { forwardRef, useImperativeHandle, useEffect, useState } from 'rea
import { Card } from 'antd';
import styles from '../supplierAnnualTaskManageAdd.less';
import SupplierSelector from '@/components/SupplierSelector';
import type { SupplierItem } from '@/servers/dao/supplierAnnualTaskManag';
import type { SupplierItem } from '@/servers/dao/supplierEvaluateTask';
import type { Dispatch } from 'umi';
import { connect } from 'umi';
import type { SupplierTaskModelState } from '@/models/supplierAnnualTaskManage';
@ -56,7 +56,7 @@ const SupplierSelectStepComponent = (props: SupplierSelectStepProps) => {
type: 'supplierAnnualTaskManage/updateFormData',
payload: {
selectedSuppliers: suppliersWithEvaluators,
supplierIds: suppliersWithEvaluators.map(supplier => ({ id: supplier.id }))
supplierIds: suppliersWithEvaluators.map(supplier => ({ suppliedId: supplier.id }))
}
});
};