Compare commits

...

2 Commits

Author SHA1 Message Date
a524a91494 评价打分和年审审核时候需要根据模板的星号项来验证 2025-08-08 14:51:02 +08:00
8d8d5eb638 模板管理新增时,获取选择模板接口增加type字段;
评价结果审批状态通过字典获取
2025-08-08 14:13:58 +08:00
12 changed files with 247 additions and 130 deletions

View File

@ -307,7 +307,7 @@ export default [
}, },
{ {
name: '年审打分', name: '年审打分',
path: 'supplierAnnual/supplierAnnualScore', path: '/supplierAnnual/supplierAnnualScore',
hideInMenu: true, hideInMenu: true,
icon: 'icon-dafen', icon: 'icon-dafen',
component: '@/pages/supplierAnnualManage/supplierAnnualReview/supplierAnnualScore', component: '@/pages/supplierAnnualManage/supplierAnnualReview/supplierAnnualScore',

View File

@ -32,4 +32,9 @@
color: #faad14; color: #faad14;
margin-left: 4px; margin-left: 4px;
} }
.required {
color: red;
vertical-align: middle;
margin-right: 5px;
}
} }

View File

@ -2,13 +2,7 @@
// 用于展示和填写供应商评价得分基于EvaluateTemplateTable组件扩展 // 用于展示和填写供应商评价得分基于EvaluateTemplateTable组件扩展
// 在二级指标中添加了评分列和说明列 // 在二级指标中添加了评分列和说明列
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import { Table, Input, InputNumber, Typography, Tooltip } from 'antd';
Table,
Input,
InputNumber,
Typography,
Tooltip,
} from 'antd';
import { useIntl } from 'umi'; import { useIntl } from 'umi';
import './ScoreEvaluationTable.less'; import './ScoreEvaluationTable.less';
@ -92,6 +86,7 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
ndScore: stItem.score || '0', ndScore: stItem.score || '0',
score: stItem.actualScore || '', score: stItem.actualScore || '',
remark: stItem.remark || '', remark: stItem.remark || '',
isStar: stItem.isStar || '',
}); });
} else { } else {
// 处理二级指标 // 处理二级指标
@ -107,7 +102,7 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
stScore: stItem.score || '0', stScore: stItem.score || '0',
subIndicator: ndItem.subIndicator || '', subIndicator: ndItem.subIndicator || '',
ndScore: ndItem.subScore || '0', ndScore: ndItem.subScore || '0',
isStar: ndItem.starIndicator || '', isStar: ndItem.isStar || '',
score: ndItem.scoreNum || '', score: ndItem.scoreNum || '',
remark: ndItem.remark || '', remark: ndItem.remark || '',
}); });
@ -125,15 +120,18 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
// 将表格数据转换回API格式 // 将表格数据转换回API格式
const convertTableDataToApiData = (tableData: TableRowItem[]): any[] => { const convertTableDataToApiData = (tableData: TableRowItem[]): any[] => {
// 按一级指标分组 // 按一级指标分组
const groupedByLevel1 = tableData.reduce((acc: Record<string, TableRowItem[]>, item: TableRowItem) => { const groupedByLevel1 = tableData.reduce(
const groupKey = item.baseIndicator || `empty-${item.key}`; (acc: Record<string, TableRowItem[]>, item: TableRowItem) => {
const groupKey = item.baseIndicator || `empty-${item.key}`;
if (!acc[groupKey]) { if (!acc[groupKey]) {
acc[groupKey] = []; acc[groupKey] = [];
} }
acc[groupKey].push(item); acc[groupKey].push(item);
return acc; return acc;
}, {}); },
{},
);
// 转换为API需要的格式 // 转换为API需要的格式
return Object.keys(groupedByLevel1).map((groupKey, stIndex) => { return Object.keys(groupedByLevel1).map((groupKey, stIndex) => {
@ -152,9 +150,10 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
subScore: item.ndScore || '0', subScore: item.ndScore || '0',
starIndicator: item.isStar || '0', starIndicator: item.isStar || '0',
scoreNum: item.score || '', scoreNum: item.score || '',
remark: item.remark || '' remark: item.remark || '',
isStar: item.isStar,
}; };
}) }),
}; };
}); });
}; };
@ -220,7 +219,9 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
if (!record.baseIndicator) return text || '-'; if (!record.baseIndicator) return text || '-';
// 查找相同baseIndicator的所有项 // 查找相同baseIndicator的所有项
const level1Items = dataSource.filter((item) => item.baseIndicator === record.baseIndicator); const level1Items = dataSource.filter(
(item) => item.baseIndicator === record.baseIndicator,
);
const index = level1Items.findIndex((item) => item.key === record.key); const index = level1Items.findIndex((item) => item.key === record.key);
if (index === 0) { if (index === 0) {
@ -245,7 +246,9 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
if (!record.baseIndicator) return text || '-'; if (!record.baseIndicator) return text || '-';
// 查找相同baseIndicator的所有项 // 查找相同baseIndicator的所有项
const level1Items = dataSource.filter((item) => item.baseIndicator === record.baseIndicator); const level1Items = dataSource.filter(
(item) => item.baseIndicator === record.baseIndicator,
);
const index = level1Items.findIndex((item) => item.key === record.key); const index = level1Items.findIndex((item) => item.key === record.key);
if (index === 0) { if (index === 0) {
@ -270,7 +273,9 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
if (!record.baseIndicator) return text || '0'; if (!record.baseIndicator) return text || '0';
// 查找相同baseIndicator的所有项 // 查找相同baseIndicator的所有项
const level1Items = dataSource.filter((item) => item.baseIndicator === record.baseIndicator); const level1Items = dataSource.filter(
(item) => item.baseIndicator === record.baseIndicator,
);
const index = level1Items.findIndex((item) => item.key === record.key); const index = level1Items.findIndex((item) => item.key === record.key);
if (index === 0) { if (index === 0) {
@ -296,7 +301,15 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
key: 'subIndicator', key: 'subIndicator',
align: 'center' as const, align: 'center' as const,
width: 200, width: 200,
render: (text: string) => text || '-', render: (text: string, record: TableRowItem) => (
<>
{/* 是否必填 1是 0否 */}
{record.isStar && record.isStar === '1' && (
<span className="required">*</span>
)}
{text || '-'}
</>
),
}, },
{ {
title: intl.formatMessage({ id: 'supplierEvaluateScore.scoreTable.subScore' }), title: intl.formatMessage({ id: 'supplierEvaluateScore.scoreTable.subScore' }),
@ -317,14 +330,18 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
return text || '-'; return text || '-';
} }
return ( return (
<InputNumber <>
min={0} <InputNumber
max={parseFloat(record.ndScore) || 0} min={0}
value={text ? parseFloat(String(text)) : undefined} max={parseFloat(record.ndScore) || 0}
onChange={(val) => handleInputChange(val, record, 'score')} value={text ? parseFloat(String(text)) : undefined}
style={{ width: '100%' }} onChange={(val) => handleInputChange(val, record, 'score')}
placeholder={intl.formatMessage({ id: 'supplierEvaluateScore.scoreTable.placeholder.score' })} style={{ width: '100%' }}
/> placeholder={intl.formatMessage({
id: 'supplierEvaluateScore.scoreTable.placeholder.score',
})}
/>
</>
); );
}, },
}, },
@ -345,7 +362,9 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
<TextArea <TextArea
value={text} value={text}
onChange={(e) => handleInputChange(e.target.value, record, 'remark')} onChange={(e) => handleInputChange(e.target.value, record, 'remark')}
placeholder={intl.formatMessage({ id: 'supplierEvaluateScore.scoreTable.placeholder.remark' })} placeholder={intl.formatMessage({
id: 'supplierEvaluateScore.scoreTable.placeholder.remark',
})}
autoSize={{ minRows: 1, maxRows: 3 }} autoSize={{ minRows: 1, maxRows: 3 }}
/> />
); );
@ -366,7 +385,9 @@ const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
size="middle" size="middle"
loading={loading} loading={loading}
scroll={{ x: 'max-content' }} scroll={{ x: 'max-content' }}
locale={{ emptyText: intl.formatMessage({ id: 'supplierEvaluateScore.scoreTable.emptyText' }) }} locale={{
emptyText: intl.formatMessage({ id: 'supplierEvaluateScore.scoreTable.emptyText' }),
}}
/> />
</div> </div>
); );

View File

@ -14,7 +14,11 @@
margin-left: auto; margin-left: auto;
} }
} }
.require{
color: red;
margin-right: 5px;
vertical-align: middle;
}
.content-area { .content-area {
} }

View File

@ -38,6 +38,7 @@ interface ScoreFormItem {
description: string; description: string;
examineResult: string; examineResult: string;
remark: string; remark: string;
isStar: string; // 是否为星号项
} }
const SupplierAnnualReviewScore: React.FC = () => { const SupplierAnnualReviewScore: React.FC = () => {
@ -76,7 +77,9 @@ const SupplierAnnualReviewScore: React.FC = () => {
message.warning(intl.formatMessage({ id: 'supplierAnnualReview.score.noScoreItemData' })); message.warning(intl.formatMessage({ id: 'supplierAnnualReview.score.noScoreItemData' }));
} }
} else { } else {
message.error(res.message || intl.formatMessage({ id: 'supplierAnnualReview.detail.getDetailFailed' })); message.error(
res.message || intl.formatMessage({ id: 'supplierAnnualReview.detail.getDetailFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('获取审查详情失败:', error); console.error('获取审查详情失败:', error);
@ -128,7 +131,9 @@ const SupplierAnnualReviewScore: React.FC = () => {
message.success(intl.formatMessage({ id: 'supplierAnnualReview.score.submitSuccess' })); message.success(intl.formatMessage({ id: 'supplierAnnualReview.score.submitSuccess' }));
history.goBack(); history.goBack();
} else { } else {
message.error(res.message || intl.formatMessage({ id: 'supplierAnnualReview.score.submitFailed' })); message.error(
res.message || intl.formatMessage({ id: 'supplierAnnualReview.score.submitFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('评审提交失败:', error); console.error('评审提交失败:', error);
@ -142,6 +147,21 @@ const SupplierAnnualReviewScore: React.FC = () => {
try { try {
// 表单验证 // 表单验证
await form.validateFields(); await form.validateFields();
const formValues = form.getFieldsValue();
const scoreVoList = scoreItems.map((item) => ({
id: item.id,
name: item.itemName,
description: item.description,
examineResult: formValues[`examineResult_${item.id}`],
remark: formValues[`remark_${item.id}`] || '',
isStar: item.isStar, // 是否为星号项
}));
// 检查所有星号项是否必填
const validateIsStar = scoreVoList.some((item) => item.isStar == '1' && !item.examineResult);
if (validateIsStar) {
message.warning('请填写所有星号项的评审结果!');
return;
}
// 确认提交 // 确认提交
Modal.confirm({ Modal.confirm({
@ -159,7 +179,8 @@ const SupplierAnnualReviewScore: React.FC = () => {
// 获取状态标签 // 获取状态标签
const getStatusTag = (status: string | undefined, statusName: string | undefined) => { const getStatusTag = (status: string | undefined, statusName: string | undefined) => {
if (!status) return <Tag>{intl.formatMessage({ id: 'supplierAnnualReview.common.unknownStatus' })}</Tag>; if (!status)
return <Tag>{intl.formatMessage({ id: 'supplierAnnualReview.common.unknownStatus' })}</Tag>;
const color = const color =
AnnualReviewStatusColor[status as keyof typeof AnnualReviewStatusColor] || 'default'; AnnualReviewStatusColor[status as keyof typeof AnnualReviewStatusColor] || 'default';
const text = const text =
@ -183,23 +204,47 @@ const SupplierAnnualReviewScore: React.FC = () => {
<Spin spinning={loading}> <Spin spinning={loading}>
{reviewDetail ? ( {reviewDetail ? (
<> <>
<Card title={intl.formatMessage({ id: 'supplierAnnualReview.score.basicInfo' })} bordered={false} className={styles['detail-card']}> <Card
title={intl.formatMessage({ id: 'supplierAnnualReview.score.basicInfo' })}
bordered={false}
className={styles['detail-card']}
>
<Descriptions column={2} bordered> <Descriptions column={2} bordered>
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.reviewTheme' })}> <Descriptions.Item
label={intl.formatMessage({ id: 'supplierAnnualReview.list.reviewTheme' })}
>
{reviewDetail.annualreviewTheme} {reviewDetail.annualreviewTheme}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.supplierName' })}> <Descriptions.Item
<a onClick={() => supplierDetailModal?.(reviewDetail.supplierId)}>{reviewDetail.name}</a> label={intl.formatMessage({ id: 'supplierAnnualReview.list.supplierName' })}
>
<a onClick={() => supplierDetailModal?.(reviewDetail.supplierId)}>
{reviewDetail.name}
</a>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.department' })}> <Descriptions.Item
label={intl.formatMessage({ id: 'supplierAnnualReview.list.department' })}
>
{reviewDetail.deptName || '-'} {reviewDetail.deptName || '-'}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.reviewer' })}> <Descriptions.Item
label={intl.formatMessage({ id: 'supplierAnnualReview.list.reviewer' })}
>
{reviewDetail.reviewerName || '-'} {reviewDetail.reviewerName || '-'}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.startTime' })}>{reviewDetail.startTime}</Descriptions.Item> <Descriptions.Item
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.endTime' })}>{reviewDetail.endTime}</Descriptions.Item> label={intl.formatMessage({ id: 'supplierAnnualReview.list.startTime' })}
<Descriptions.Item label={intl.formatMessage({ id: 'supplierAnnualReview.list.status' })}> >
{reviewDetail.startTime}
</Descriptions.Item>
<Descriptions.Item
label={intl.formatMessage({ id: 'supplierAnnualReview.list.endTime' })}
>
{reviewDetail.endTime}
</Descriptions.Item>
<Descriptions.Item
label={intl.formatMessage({ id: 'supplierAnnualReview.list.status' })}
>
{reviewDetail.reviewStatusName || '-'} {reviewDetail.reviewStatusName || '-'}
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
@ -207,7 +252,11 @@ const SupplierAnnualReviewScore: React.FC = () => {
<Divider /> <Divider />
<Card title={intl.formatMessage({ id: 'supplierAnnualReview.score.examineResult' })} bordered={false} className={styles['detail-card']}> <Card
title={intl.formatMessage({ id: 'supplierAnnualReview.score.examineResult' })}
bordered={false}
className={styles['detail-card']}
>
<Form form={form} layout="vertical" className={styles['score-form']}> <Form form={form} layout="vertical" className={styles['score-form']}>
{scoreItems.length > 0 ? ( {scoreItems.length > 0 ? (
<Table <Table
@ -221,20 +270,22 @@ const SupplierAnnualReviewScore: React.FC = () => {
title: intl.formatMessage({ id: 'supplierAnnualReview.score.scoreItem' }), title: intl.formatMessage({ id: 'supplierAnnualReview.score.scoreItem' }),
dataIndex: 'itemName', dataIndex: 'itemName',
width: '15%', width: '15%',
render: (text, record) => (
<div>
{record.isStar == '1' && <span className={styles['require']}>*</span>}
{text}
</div>
),
}, },
// {
// title: intl.formatMessage({ id: 'supplierAnnualReview.score.scoreItemDesc' }),
// dataIndex: 'description',
// width: '25%',
// },
{ {
title: intl.formatMessage({ id: 'supplierAnnualReview.detail.examineResult' }), title: intl.formatMessage({
id: 'supplierAnnualReview.detail.examineResult',
}),
dataIndex: 'examineResult', dataIndex: 'examineResult',
width: '25%', width: '25%',
render: (_, record) => ( render: (_, record) => (
<Form.Item <Form.Item
name={`examineResult_${record.id}`} name={`examineResult_${record.id}`}
rules={[{ required: true, message: intl.formatMessage({ id: 'supplierAnnualReview.score.pleaseSelectResult' }) }]}
style={{ marginBottom: 0 }} style={{ marginBottom: 0 }}
> >
<Radio.Group> <Radio.Group>
@ -249,17 +300,18 @@ const SupplierAnnualReviewScore: React.FC = () => {
), ),
}, },
{ {
title: intl.formatMessage({ id: 'supplierAnnualReview.score.examineRemark' }), title: intl.formatMessage({
id: 'supplierAnnualReview.score.examineRemark',
}),
dataIndex: 'remark', dataIndex: 'remark',
width: '35%', width: '35%',
render: (_, record) => ( render: (_, record) => (
<Form.Item <Form.Item name={`remark_${record.id}`} style={{ marginBottom: 0 }}>
name={`remark_${record.id}`}
style={{ marginBottom: 0 }}
>
<TextArea <TextArea
rows={2} rows={2}
placeholder={intl.formatMessage({ id: 'supplierAnnualReview.score.pleaseInputRemark' })} placeholder={intl.formatMessage({
id: 'supplierAnnualReview.score.pleaseInputRemark',
})}
maxLength={200} maxLength={200}
/> />
</Form.Item> </Form.Item>
@ -268,7 +320,11 @@ const SupplierAnnualReviewScore: React.FC = () => {
]} ]}
/> />
) : ( ) : (
<Empty description={intl.formatMessage({ id: 'supplierAnnualReview.score.noScoreItemData' })} /> <Empty
description={intl.formatMessage({
id: 'supplierAnnualReview.score.noScoreItemData',
})}
/>
)} )}
<div className={styles['score-actions']}> <div className={styles['score-actions']}>
@ -285,7 +341,11 @@ const SupplierAnnualReviewScore: React.FC = () => {
</Card> </Card>
</> </>
) : ( ) : (
!loading && <Empty description={intl.formatMessage({ id: 'supplierAnnualReview.detail.noDetailData' })} /> !loading && (
<Empty
description={intl.formatMessage({ id: 'supplierAnnualReview.detail.noDetailData' })}
/>
)
)} )}
</Spin> </Spin>
</Card> </Card>

View File

@ -79,7 +79,7 @@ const SupplierAnnualTemplateManageAdd: React.FC<PageProps> = ({ breadcrumb, disp
const fetchTemplateList = async () => { const fetchTemplateList = async () => {
try { try {
setLoading(true); setLoading(true);
const res = await getAllAnnualTemplates({ status: '1' }); const res = await getAllAnnualTemplates({ status: '1', type: 'currentUnit' });
if (res.success && res.data) { if (res.success && res.data) {
// 如果是修改,需要过滤掉自己 // 如果是修改,需要过滤掉自己
if (location.state?.editData) { if (location.state?.editData) {
@ -144,7 +144,7 @@ const SupplierAnnualTemplateManageAdd: React.FC<PageProps> = ({ breadcrumb, disp
if (location.state?.editData?.id && dispatch) { if (location.state?.editData?.id && dispatch) {
dispatch({ dispatch({
type: 'breadcrumb/updateBreadcrumbName', type: 'breadcrumb/updateBreadcrumbName',
payload: intl.formatMessage({ id: "supplierAnnualTemplateManage.add.edit" }), payload: intl.formatMessage({ id: 'supplierAnnualTemplateManage.add.edit' }),
}); });
} }

View File

@ -13,17 +13,17 @@ import {
message, message,
} from 'antd'; } from 'antd';
import type { TablePaginationConfig } from 'antd'; import type { TablePaginationConfig } from 'antd';
import { import { SearchOutlined, DeleteOutlined } from '@ant-design/icons';
SearchOutlined,
DeleteOutlined,
} from '@ant-design/icons';
import { TaskStatusText, TaskStatusColor } from '@/dicts/supplierTaskDict'; import { TaskStatusText, TaskStatusColor } from '@/dicts/supplierTaskDict';
import { history, useIntl } from 'umi'; import { history, useIntl } from 'umi';
import { getEvaluateResultList, submitTaskForApproval, supplierChangeApprove } from '@/servers/api/supplierEvaluate'; import {
getEvaluateResultList,
submitTaskForApproval,
supplierChangeApprove,
} from '@/servers/api/supplierEvaluate';
import { getDictList } from '@/servers/api/dicts'; import { getDictList } from '@/servers/api/dicts';
import type { DictItem } from '@/servers/api/dicts'; import type { DictItem } from '@/servers/api/dicts';
import { render } from 'react-dom';
// 扩展评价任务搜索参数类型 // 扩展评价任务搜索参数类型
interface EvaluateTaskSearchParams { interface EvaluateTaskSearchParams {
@ -33,29 +33,26 @@ interface EvaluateTaskSearchParams {
[key: string]: any; [key: string]: any;
} }
const { Option } = Select; const { Option } = Select;
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
const SupplierEvaluateResult: React.FC = () => { const SupplierEvaluateResult: React.FC = () => {
const userId = sessionStorage.getItem('userId') || ''; const userId = sessionStorage.getItem('userId') || '';
const intl = useIntl(); const intl = useIntl();
const [loading, setLoading] = useState < boolean > (false); const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm(); const [form] = Form.useForm();
const [resultData, setResultData] = useState < SupplierEvaluateResult.EvaluateTaskItem[] > ([]); const [resultData, setResultData] = useState<SupplierEvaluateResult.EvaluateTaskItem[]>([]);
const [pagination, setPagination] = useState < TablePaginationConfig > ({ const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1, current: 1,
pageSize: 10, pageSize: 10,
total: 0, total: 0,
showSizeChanger: true, showSizeChanger: true,
showQuickJumper: true, showQuickJumper: true,
showTotal: (total) => intl.formatMessage( showTotal: (total) =>
{ id: 'supplierEvaluateResult.pagination.total' }, intl.formatMessage({ id: 'supplierEvaluateResult.pagination.total' }, { total }),
{ total }
),
}); });
const [searchParams, setSearchParams] = useState < EvaluateTaskSearchParams > ({}); const [searchParams, setSearchParams] = useState<EvaluateTaskSearchParams>({});
const [evaluateStatus, setEvaluateStatus] = useState < DictItem[] > ([]); const [evaluateStatus, setEvaluateStatus] = useState<DictItem[]>([]);
// 获取评价结果列表 // 获取评价结果列表
const fetchResultList = async ( const fetchResultList = async (
current = 1, current = 1,
@ -75,7 +72,7 @@ const SupplierEvaluateResult: React.FC = () => {
pageNo: current, pageNo: current,
pageSize: pageSize, pageSize: pageSize,
}, },
selectBy: "create", selectBy: 'create',
}; };
// 添加搜索条件 // 添加搜索条件
@ -96,7 +93,7 @@ const SupplierEvaluateResult: React.FC = () => {
const { records, total, current: currentPage, size } = response.data; const { records, total, current: currentPage, size } = response.data;
// 处理数据增加表格需要的key属性 // 处理数据增加表格需要的key属性
const formattedData = records.map(record => ({ const formattedData = records.map((record) => ({
...record, ...record,
key: record.id, key: record.id,
})); }));
@ -109,7 +106,10 @@ const SupplierEvaluateResult: React.FC = () => {
total, total,
}); });
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateResult.message.fetchFailed' })); message.error(
response.message ||
intl.formatMessage({ id: 'supplierEvaluateResult.message.fetchFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('获取评价结果列表失败:', error); console.error('获取评价结果列表失败:', error);
@ -118,6 +118,7 @@ const SupplierEvaluateResult: React.FC = () => {
setLoading(false); setLoading(false);
} }
}; };
const [approveTypeList, setApproveTypeList] = useState<DictItem[]>([]);
// 首次加载获取数据 // 首次加载获取数据
useEffect(() => { useEffect(() => {
@ -127,6 +128,12 @@ const SupplierEvaluateResult: React.FC = () => {
setEvaluateStatus(res.data); setEvaluateStatus(res.data);
} }
}); });
// 获取审批状态字典
getDictList('approve_type').then((res) => {
if (res.success) {
setApproveTypeList(res.data);
}
});
}, []); }, []);
// 处理表格分页变化 // 处理表格分页变化
@ -158,7 +165,7 @@ const SupplierEvaluateResult: React.FC = () => {
title: intl.formatMessage({ id: 'supplierEvaluateResult.confirm.title' }), title: intl.formatMessage({ id: 'supplierEvaluateResult.confirm.title' }),
content: intl.formatMessage( content: intl.formatMessage(
{ id: 'supplierEvaluateResult.confirm.content' }, { id: 'supplierEvaluateResult.confirm.content' },
{ theme: record.evaluateTheme } { theme: record.evaluateTheme },
), ),
okText: intl.formatMessage({ id: 'supplierEvaluateResult.confirm.ok' }), okText: intl.formatMessage({ id: 'supplierEvaluateResult.confirm.ok' }),
cancelText: intl.formatMessage({ id: 'supplierEvaluateResult.confirm.cancel' }), cancelText: intl.formatMessage({ id: 'supplierEvaluateResult.confirm.cancel' }),
@ -166,17 +173,22 @@ const SupplierEvaluateResult: React.FC = () => {
try { try {
const response = await submitTaskForApproval(record.id); const response = await submitTaskForApproval(record.id);
if (response.success) { if (response.success) {
message.success(intl.formatMessage({ id: 'supplierEvaluateResult.message.approveSuccess' })); message.success(
intl.formatMessage({ id: 'supplierEvaluateResult.message.approveSuccess' }),
);
// 刷新数据 // 刷新数据
fetchResultList(pagination.current, pagination.pageSize, searchParams); fetchResultList(pagination.current, pagination.pageSize, searchParams);
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateResult.message.approveFailed' })); message.error(
response.message ||
intl.formatMessage({ id: 'supplierEvaluateResult.message.approveFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('提交审批失败:', error); console.error('提交审批失败:', error);
message.error(intl.formatMessage({ id: 'supplierEvaluateResult.message.approveError' })); message.error(intl.formatMessage({ id: 'supplierEvaluateResult.message.approveError' }));
} }
} },
}); });
}; };
@ -184,11 +196,10 @@ const SupplierEvaluateResult: React.FC = () => {
const handleViewDetail = (record: SupplierEvaluateResult.EvaluateTaskItem) => { const handleViewDetail = (record: SupplierEvaluateResult.EvaluateTaskItem) => {
history.push({ history.push({
pathname: 'supplierEvaluateResultInfo', pathname: 'supplierEvaluateResultInfo',
state: { record } state: { record },
}); });
}; };
const columns = [ const columns = [
{ {
title: intl.formatMessage({ id: 'supplierEvaluateResult.column.index' }), title: intl.formatMessage({ id: 'supplierEvaluateResult.column.index' }),
@ -219,7 +230,10 @@ const SupplierEvaluateResult: React.FC = () => {
showTitle: false, showTitle: false,
}, },
render: (text: string) => ( render: (text: string) => (
<Tooltip placement="topLeft" title={text || intl.formatMessage({ id: 'supplierEvaluateResult.text.unspecified' })}> <Tooltip
placement="topLeft"
title={text || intl.formatMessage({ id: 'supplierEvaluateResult.text.unspecified' })}
>
{text || intl.formatMessage({ id: 'supplierEvaluateResult.text.unspecified' })} {text || intl.formatMessage({ id: 'supplierEvaluateResult.text.unspecified' })}
</Tooltip> </Tooltip>
), ),
@ -258,9 +272,12 @@ const SupplierEvaluateResult: React.FC = () => {
}, },
{ {
title: intl.formatMessage({ id: 'supplierEvaluateResult.column.approveName' }), title: intl.formatMessage({ id: 'supplierEvaluateResult.column.approveName' }),
dataIndex: 'approveName', dataIndex: 'approveStatus',
key: 'approveName', key: 'approveStatus',
width: 100, width: 100,
render: (text: string, record: any) => (
<div>{approveTypeList.find((item) => item.code === text)?.dicName || '-'}</div>
),
}, },
{ {
title: intl.formatMessage({ id: 'supplierEvaluateResult.column.action' }), title: intl.formatMessage({ id: 'supplierEvaluateResult.column.action' }),
@ -278,11 +295,16 @@ const SupplierEvaluateResult: React.FC = () => {
</Button> </Button>
)} )}
{record.approveStatus === '0' && userId == '8' && ( {record.approveStatus === '0' && userId == '8' && (
<Button type="link" onClick={() => { <Button
supplierChangeApprove({ workFlowId: record.workFlowId, approveStatus: '1' }).then(() => { type="link"
handleReset() onClick={() => {
}) supplierChangeApprove({ workFlowId: record.workFlowId, approveStatus: '1' }).then(
}}> () => {
handleReset();
},
);
}}
>
</Button> </Button>
)} )}
@ -294,27 +316,38 @@ const SupplierEvaluateResult: React.FC = () => {
return ( return (
<div className="common-container"> <div className="common-container">
<div className="filter-action-row"> <div className="filter-action-row">
<Form <Form form={form} layout="inline" onFinish={handleSearch} className="filter-form">
form={form} <Form.Item
layout="inline" name="evaluateTheme"
onFinish={handleSearch} label={intl.formatMessage({ id: 'supplierEvaluateResult.form.evaluateTheme' })}
className="filter-form" >
> <Input
<Form.Item name="evaluateTheme" label={intl.formatMessage({ id: 'supplierEvaluateResult.form.evaluateTheme' })}> placeholder={intl.formatMessage({
<Input placeholder={intl.formatMessage({ id: 'supplierEvaluateResult.form.placeholder.evaluateTheme' })} allowClear /> id: 'supplierEvaluateResult.form.placeholder.evaluateTheme',
})}
allowClear
/>
</Form.Item> </Form.Item>
<Form.Item name="timeRange" label={intl.formatMessage({ id: 'supplierEvaluateResult.form.evaluationTime' })}> <Form.Item
name="timeRange"
label={intl.formatMessage({ id: 'supplierEvaluateResult.form.evaluationTime' })}
>
<RangePicker <RangePicker
placeholder={[ placeholder={[
intl.formatMessage({ id: 'supplierEvaluateResult.form.placeholder.startDate' }), intl.formatMessage({ id: 'supplierEvaluateResult.form.placeholder.startDate' }),
intl.formatMessage({ id: 'supplierEvaluateResult.form.placeholder.endDate' }) intl.formatMessage({ id: 'supplierEvaluateResult.form.placeholder.endDate' }),
]} ]}
format="YYYY-MM-DD" format="YYYY-MM-DD"
/> />
</Form.Item> </Form.Item>
<Form.Item name="status" label={intl.formatMessage({ id: 'supplierEvaluateResult.form.status' })}> <Form.Item
name="status"
label={intl.formatMessage({ id: 'supplierEvaluateResult.form.status' })}
>
<Select <Select
placeholder={intl.formatMessage({ id: 'supplierEvaluateResult.form.placeholder.status' })} placeholder={intl.formatMessage({
id: 'supplierEvaluateResult.form.placeholder.status',
})}
allowClear allowClear
style={{ width: 150 }} style={{ width: 150 }}
> >
@ -329,12 +362,7 @@ const SupplierEvaluateResult: React.FC = () => {
<Button type="primary" icon={<SearchOutlined />} onClick={() => form.submit()}> <Button type="primary" icon={<SearchOutlined />} onClick={() => form.submit()}>
{intl.formatMessage({ id: 'supplierEvaluateResult.button.search' })} {intl.formatMessage({ id: 'supplierEvaluateResult.button.search' })}
</Button> </Button>
<Button <Button type="primary" danger icon={<DeleteOutlined />} onClick={handleReset}>
type="primary"
danger
icon={<DeleteOutlined />}
onClick={handleReset}
>
{intl.formatMessage({ id: 'supplierEvaluateResult.button.reset' })} {intl.formatMessage({ id: 'supplierEvaluateResult.button.reset' })}
</Button> </Button>
</Form.Item> </Form.Item>

View File

@ -84,10 +84,10 @@ const SupplierEvaluateScoreDetail: React.FC = () => {
id: subItem.id, id: subItem.id,
subIndicator: subItem.subIndicator, subIndicator: subItem.subIndicator,
subScore: subItem.subScore, // 二级指标标准分值 subScore: subItem.subScore, // 二级指标标准分值
isStar: subItem.starIndicator,
scoreNum: subItem.score || '', // 实际评分值使用API返回的score字段 scoreNum: subItem.score || '', // 实际评分值使用API返回的score字段
score: subItem.score || '', // 组件内部显示用 score: subItem.score || '', // 组件内部显示用
remark: subItem.remark || '', remark: subItem.remark || '',
isStar: subItem.isStar, // 是否必填
}; };
}) })
.filter(Boolean) || [], .filter(Boolean) || [],
@ -151,12 +151,12 @@ const SupplierEvaluateScoreDetail: React.FC = () => {
const hasEmptyScore = scoreData.some((item) => const hasEmptyScore = scoreData.some((item) =>
item.indicatorNdList.some((subItem: any) => { item.indicatorNdList.some((subItem: any) => {
// 使用scoreNum字段检查是否已评分 // 使用scoreNum字段检查是否已评分
return !subItem.scoreNum && subItem.scoreNum !== 0; return !subItem.scoreNum && subItem.scoreNum !== 0 && subItem.isStar === '1'; // 只检查必填项
}), }),
); );
if (hasEmptyScore) { if (hasEmptyScore) {
message.warning(intl.formatMessage({ id: 'supplierEvaluateScore.message.emptyScore' })); message.warning("请填写所有必填项的评分!");
return; return;
} }

View File

@ -316,7 +316,7 @@ const handleDisableTemplate = (id: string) => {
name="tenantName" name="tenantName"
label={intl.formatMessage({ id: 'supplierTemplateManage.column.tenantName' })} label={intl.formatMessage({ id: 'supplierTemplateManage.column.tenantName' })}
> >
<AccessDepartmentSelect placeholder={'请选择准入单位'} /> <AccessDepartmentSelect placeholder={'请选择创建单位'} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="categoryId" name="categoryId"

View File

@ -92,7 +92,7 @@ const SupplierTemplateManageAdd: React.FC<PageProps> = ({ breadcrumb, dispatch }
// 获取所有模板列表 // 获取所有模板列表
const fetchTemplateList = async () => { const fetchTemplateList = async () => {
try { try {
const res = await getAllTemplates({ status: '1' }); const res = await getAllTemplates({ status: '1', type: 'currentUnit' });
if (res.success && res.data) { if (res.success && res.data) {
// 如果是修改,需要过滤掉自己 // 如果是修改,需要过滤掉自己
if (location.state?.editData) { if (location.state?.editData) {
@ -234,10 +234,9 @@ const SupplierTemplateManageAdd: React.FC<PageProps> = ({ breadcrumb, dispatch }
// 校验每个一级指标下的二级指标之和是否等于该一级指标分值 // 校验每个一级指标下的二级指标之和是否等于该一级指标分值
for (const stItem of templateData) { for (const stItem of templateData) {
const firstLevelScore = parseFloat(stItem.score || '0'); const firstLevelScore = parseFloat(stItem.score || '0');
const secondLevelTotal = stItem.indicatorNdList?.reduce( const secondLevelTotal =
(acc, ndItem) => acc + parseFloat(ndItem.score || '0'), stItem.indicatorNdList?.reduce((acc, ndItem) => acc + parseFloat(ndItem.score || '0'), 0) ||
0, 0;
) || 0;
if (secondLevelTotal !== firstLevelScore) { if (secondLevelTotal !== firstLevelScore) {
message.error(`二级指标分值之和必须等于其一级指标的分值`); message.error(`二级指标分值之和必须等于其一级指标的分值`);
@ -305,8 +304,8 @@ const SupplierTemplateManageAdd: React.FC<PageProps> = ({ breadcrumb, dispatch }
message.error(intl.formatMessage({ id: 'supplierTemplateManage.message.addIndicator' })); message.error(intl.formatMessage({ id: 'supplierTemplateManage.message.addIndicator' }));
return; return;
} }
// 校验分数 // 校验分数
if (!validateScore()) { if (!validateScore()) {
return; return;
} }

View File

@ -18,7 +18,7 @@ export async function getAnnualTemplateList(params: supplierAnnualTemplateManage
* 获取所有供应商年度模板列表 * 获取所有供应商年度模板列表
* @returns Promise * @returns Promise
*/ */
export async function getAllAnnualTemplates(params?: {status: string}) { export async function getAllAnnualTemplates(params?: { status: string, type: string }) {
return request<supplierAnnualTemplateManage.AllTemplatesResponse>('/annualreview/template/getAllList', { return request<supplierAnnualTemplateManage.AllTemplatesResponse>('/annualreview/template/getAllList', {
method: 'GET', method: 'GET',
params params

View File

@ -3,7 +3,7 @@ import request from '@/utils/request';
* 获取所有模板列表 * 获取所有模板列表
* @returns 所有模板列表 * @returns 所有模板列表
*/ */
export async function getAllTemplates(params?: {status: string}) { export async function getAllTemplates(params?: { status: string, type: string }) {
return request('/coscoEvaluate/template/getAllList', { return request('/coscoEvaluate/template/getAllList', {
method: 'GET', method: 'GET',
params params
@ -362,4 +362,4 @@ export async function submitTaskForApproval(id: string) {
}); });
} }
export const supplierChangeApprove = (data: { workFlowId:string; approveStatus:string }) => request.post('/synchronous/evaluateApprove', { data }); export const supplierChangeApprove = (data: { workFlowId: string; approveStatus: string }) => request.post('/synchronous/evaluateApprove', { data });