对接评价结果接口

This commit is contained in:
linxd
2025-06-24 14:00:51 +08:00
parent 0375e369de
commit 6f4efad67b
32 changed files with 2069 additions and 1936 deletions

View File

@ -75,6 +75,15 @@ export default [
},
component: '@/pages/supplierEvaluateManage/supplierTemplateManage/supplierTemplateManageDetail',
},
{
name: 'supplierEvaluateRuleManage',
path: 'supplierEvaluateRuleManage',
meta: {
title: '评价规则管理',
icon: 'icon-liebiaomoshi',
},
component: '@/pages/supplierEvaluateManage/supplierEvaluateRuleManage/supplierEvaluateRuleManage',
},
{
name: 'supplierTaskManage',
path: 'supplierTaskManage',
@ -225,7 +234,7 @@ export default [
path: '/backend',
name: 'backend',
icon: 'smile',
component: '@/layouts/MainLayout',
component: '@/layouts/MainLayout',
routes: [
{
path: '/backend/workbenches',
@ -257,7 +266,7 @@ export default [
path: '/informationRetrieval',
name: 'informationRetrieval',
icon: 'smile',
component: '@/layouts/MainLayout',
component: '@/layouts/MainLayout',
routes: [
{
path: '/informationRetrieval/registrationQuery',
@ -283,7 +292,7 @@ export default [
path: '/informationManagement',
name: 'informationManagement',
icon: 'smile',
component: '@/layouts/MainLayout',
component: '@/layouts/MainLayout',
routes: [
{
path: '/informationManagement/SupplierRegisterAgent',
@ -309,7 +318,7 @@ export default [
path: '/admission',
name: 'admission',
icon: 'smile',
component: '@/layouts/MainLayout',
component: '@/layouts/MainLayout',
routes: [
{
path: '/admission/admissionManagement',
@ -347,7 +356,7 @@ export default [
path: '/category',
name: 'category',
icon: 'smile',
component: '@/layouts/MainLayout',
component: '@/layouts/MainLayout',
routes: [
{
path: '/category/category-manage',
@ -385,7 +394,7 @@ export default [
path: '/supplierBlacklist',
name: 'supplierBlacklist',
icon: 'smile',
component: '@/layouts/MainLayout',
component: '@/layouts/MainLayout',
routes: [
{
path: '/supplierBlacklist/manage',

View File

@ -454,7 +454,7 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
key: 'index',
width: 50,
render: (_: any, record: TableRowItem, index: number) => {
return renderWithRowSpan(index + 1, record, (cellContent) => cellContent);
return <>{index + 1}</>;
},
},
{

View File

@ -0,0 +1,90 @@
# ScoreEvaluationTable 评分表格组件
## 组件介绍
ScoreEvaluationTable 是一个用于展示和填写供应商评价得分的表格组件。该组件基于 EvaluateTemplateTable 组件扩展,在二级指标中添加了评分列和说明列,可用于评价结果的展示和评分录入。
## 功能特点
- 支持一级指标和二级指标的层级展示
- 支持评分和评分说明的录入和展示
- 支持详情模式(只读)和编辑模式
- 支持数据格式的自动转换
- 自动合并一级指标单元格
## 使用方法
```tsx
import ScoreEvaluationTable from '@/components/ScoreEvaluationTable';
// 示例数据
const evaluationData = [
{
id: '1',
baseIndicator: '质量管理',
descIndicator: '质量管理体系完善程度',
score: '30',
indicatorNdList: [
{
id: '1-1',
subIndicator: '质量管理体系认证',
score: '10',
isStar: '0',
actualScore: '8',
remark: '已获得ISO9001认证'
},
{
id: '1-2',
subIndicator: '质量控制流程',
score: '10',
isStar: '1',
actualScore: '9',
remark: '质量控制流程完善'
}
]
}
];
// 详情模式(只读)
<ScoreEvaluationTable
value={evaluationData}
isDetail={true}
/>
// 编辑模式
<ScoreEvaluationTable
value={evaluationData}
onChange={(newData) => console.log(newData)}
isDetail={false}
/>
```
## 属性说明
| 属性名 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| value | array | [] | 表格数据应符合API返回的评价指标数据结构 |
| onChange | function | - | 数据变更回调函数 |
| isDetail | boolean | false | 是否为详情模式(只读) |
| loading | boolean | false | 表格加载状态 |
## 数据格式
组件接受的数据格式应为一个数组,每个元素代表一个一级指标,包含以下字段:
```typescript
interface IndicatorItem {
id?: string; // 一级指标ID
baseIndicator: string; // 一级指标名称
descIndicator?: string; // 一级指标说明
score: string; // 一级指标分值
indicatorNdList: { // 二级指标列表
id?: string; // 二级指标ID
subIndicator: string; // 二级指标名称
score: string; // 二级指标分值
isStar?: string; // 是否为星号项
actualScore?: string; // 实际评分
remark?: string; // 评分说明
}[];
}
```

View File

@ -0,0 +1,35 @@
// 评分表格样式
.score-evaluation-table {
margin-bottom: 16px;
.ant-table-thead > tr > th {
background-color: #f5f5f5;
font-weight: 500;
}
.ant-table-tbody > tr > td {
padding: 8px;
}
.ellipsis-text {
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
// 评分列样式
.low-score {
color: #ff4d4f;
}
.high-score {
color: #52c41a;
}
// 星号项样式
.star-item {
color: #faad14;
margin-left: 4px;
}
}

View File

@ -0,0 +1,370 @@
// 供应商评价得分表格组件
// 用于展示和填写供应商评价得分基于EvaluateTemplateTable组件扩展
// 在二级指标中添加了评分列和说明列
import React, { useState, useEffect } from 'react';
import {
Table,
Input,
InputNumber,
Typography,
Tooltip,
} from 'antd';
import './ScoreEvaluationTable.less';
const { Text } = Typography;
const { TextArea } = Input;
/**
* 评分表格组件属性
*/
interface ScoreEvaluationTableProps {
/**
* 表格数据应符合API返回的评价指标数据结构
*/
value?: any[];
/**
* 数据变更回调函数
*/
onChange?: (value: any[]) => void;
/**
* 是否为详情模式(只读)
*/
isDetail?: boolean;
/**
* 表格加载状态
*/
loading?: boolean;
}
/**
* 内部使用的表格行数据结构
*/
interface TableRowItem {
key: string;
stId?: string; // 一级指标ID
ndId?: string; // 二级指标ID
baseIndicator: string; // 一级指标名称
descIndicator?: string; // 一级指标说明
stScore: string; // 一级指标分值
subIndicator: string; // 二级指标名称
ndScore: string; // 二级指标分值
isStar?: string; // 是否为星号项
score?: string | number; // 实际评分
remark?: string; // 评分说明
}
/**
* 供应商评价得分表格组件
* 用于展示和填写供应商评价得分,支持详情模式和编辑模式
*/
const ScoreEvaluationTable: React.FC<ScoreEvaluationTableProps> = ({
value = [],
onChange,
isDetail = false,
loading = false,
}) => {
// 表格数据源
const [dataSource, setDataSource] = useState<TableRowItem[]>([]);
// 将API数据转换为表格数据
const convertApiDataToTableData = (apiData: any[]): TableRowItem[] => {
// 检查数据是否已经是扁平化的表格数据格式
if (apiData.length > 0 && 'subIndicator' in apiData[0]) {
return apiData as TableRowItem[];
}
// 如果是嵌套结构,需要扁平化处理
if (apiData.length > 0 && 'indicatorNdList' in apiData[0]) {
const flattenedData: TableRowItem[] = [];
apiData.forEach((stItem: any, stIndex: number) => {
if (!stItem.indicatorNdList || stItem.indicatorNdList.length === 0) {
// 如果没有二级指标,添加一个空的二级指标行
flattenedData.push({
key: `${stItem.id || stIndex}-0`,
stId: stItem.id,
baseIndicator: stItem.baseIndicator || '',
descIndicator: stItem.descIndicator || '',
stScore: stItem.score || '0',
subIndicator: '',
ndScore: '0',
score: stItem.actualScore || '',
remark: stItem.remark || '',
});
} else {
// 处理二级指标
stItem.indicatorNdList.forEach((ndItem: any, ndIndex: number) => {
flattenedData.push({
key: `${stItem.id || stIndex}-${ndItem.id || ndIndex}`,
stId: stItem.id,
ndId: ndItem.id,
baseIndicator: stItem.baseIndicator || '',
descIndicator: stItem.descIndicator || '',
stScore: stItem.score || '0',
subIndicator: ndItem.subIndicator || '',
ndScore: ndItem.score || '0',
isStar: ndItem.isStar || '',
score: ndItem.actualScore || '',
remark: ndItem.remark || '',
});
});
}
});
return flattenedData;
}
return [];
};
// 将表格数据转换回API格式
const convertTableDataToApiData = (tableData: TableRowItem[]): any[] => {
// 按一级指标分组
const groupedByLevel1 = tableData.reduce((acc: Record<string, TableRowItem[]>, item: TableRowItem) => {
const groupKey = item.baseIndicator || `empty-${item.key}`;
if (!acc[groupKey]) {
acc[groupKey] = [];
}
acc[groupKey].push(item);
return acc;
}, {});
// 转换为API需要的格式
return Object.keys(groupedByLevel1).map((groupKey, stIndex) => {
const level1Items = groupedByLevel1[groupKey];
const firstItem = level1Items[0];
return {
id: firstItem.stId || `temp-st-${stIndex}`,
baseIndicator: firstItem.baseIndicator || '',
descIndicator: firstItem.descIndicator || '',
score: firstItem.stScore || '0',
indicatorNdList: level1Items.map((item, ndIndex) => {
return {
id: item.ndId || `temp-nd-${stIndex}-${ndIndex}`,
subIndicator: item.subIndicator || '',
score: item.ndScore || '0',
isStar: item.isStar || '',
actualScore: item.score || '',
remark: item.remark || ''
};
})
};
});
};
// 单独处理value变化
useEffect(() => {
if (value && value.length > 0) {
const tableData = convertApiDataToTableData(value);
setDataSource(tableData);
} else {
setDataSource([]);
}
}, [value]);
// 更新数据源
const updateDataSource = (newData: TableRowItem[]) => {
setDataSource(newData);
if (onChange) {
// 转换回API格式再传递给父组件
const apiData = convertTableDataToApiData(newData);
onChange(apiData);
}
};
// 处理输入变化
const handleInputChange = (val: any, record: TableRowItem, field: string) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => item.key === record.key);
if (index > -1) {
newData[index] = { ...newData[index], [field]: val };
updateDataSource(newData);
}
};
// 获取一级指标的行数
const getLevel1RowSpan = (baseIndicator: string) => {
if (!baseIndicator) return 1;
return dataSource.filter((item) => item.baseIndicator === baseIndicator).length;
};
const columns = [
{
title: '一级指标',
children: [
{
title: '序号',
dataIndex: 'index',
align: 'center' as const,
key: 'index',
width: 50,
render: (_: any, record: TableRowItem, index: number) => {
return <>{index + 1}</>;
},
},
{
title: '基本指标',
align: 'center' as const,
dataIndex: 'baseIndicator',
key: 'baseIndicator',
width: 150,
render: (text: string, record: TableRowItem) => {
if (!record.baseIndicator) return text || '-';
// 查找相同baseIndicator的所有项
const level1Items = dataSource.filter((item) => item.baseIndicator === record.baseIndicator);
const index = level1Items.findIndex((item) => item.key === record.key);
if (index === 0) {
return {
children: text || '-',
props: { rowSpan: level1Items.length },
};
}
return {
props: { rowSpan: 0 },
};
},
},
{
title: '指标说明',
align: 'center' as const,
dataIndex: 'descIndicator',
key: 'descIndicator',
width: 200,
render: (text: string, record: TableRowItem) => {
if (!record.baseIndicator) return text || '-';
// 查找相同baseIndicator的所有项
const level1Items = dataSource.filter((item) => item.baseIndicator === record.baseIndicator);
const index = level1Items.findIndex((item) => item.key === record.key);
if (index === 0) {
return {
children: text || '-',
props: { rowSpan: level1Items.length },
};
}
return {
props: { rowSpan: 0 },
};
},
},
{
title: '分值',
align: 'center' as const,
dataIndex: 'stScore',
key: 'stScore',
width: 80,
render: (text: string, record: TableRowItem) => {
if (!record.baseIndicator) return text || '0';
// 查找相同baseIndicator的所有项
const level1Items = dataSource.filter((item) => item.baseIndicator === record.baseIndicator);
const index = level1Items.findIndex((item) => item.key === record.key);
if (index === 0) {
return {
children: text || '0',
props: { rowSpan: level1Items.length },
};
}
return {
props: { rowSpan: 0 },
};
},
},
],
},
{
title: '二级指标',
children: [
{
title: '细分指标',
dataIndex: 'subIndicator',
key: 'subIndicator',
align: 'center' as const,
width: 200,
render: (text: string) => text || '-',
},
{
title: '分值',
dataIndex: 'ndScore',
key: 'ndScore',
width: 80,
align: 'center' as const,
render: (text: string) => text || '0',
},
{
title: '评分',
dataIndex: 'score',
key: 'score',
width: 100,
align: 'center' as const,
render: (text: string | number, record: TableRowItem) => {
if (isDetail) {
return text || '-';
}
return (
<InputNumber
min={0}
max={parseFloat(record.ndScore) || 100}
value={text ? parseFloat(String(text)) : undefined}
onChange={(val) => handleInputChange(val, record, 'score')}
style={{ width: '100%' }}
placeholder="请输入评分"
/>
);
},
},
{
title: '评分说明',
dataIndex: 'remark',
key: 'remark',
width: 200,
render: (text: string, record: TableRowItem) => {
if (isDetail) {
return (
<Tooltip title={text}>
<div className="ellipsis-text">{text || '-'}</div>
</Tooltip>
);
}
return (
<TextArea
value={text}
onChange={(e) => handleInputChange(e.target.value, record, 'remark')}
placeholder="请输入评分说明"
autoSize={{ minRows: 1, maxRows: 3 }}
/>
);
},
},
],
},
];
return (
<div className="score-evaluation-table">
<Table
columns={columns}
dataSource={dataSource}
pagination={false}
bordered
rowKey="key"
size="middle"
loading={loading}
scroll={{ x: 'max-content' }}
locale={{ emptyText: '无数据' }}
/>
</div>
);
};
export default ScoreEvaluationTable;

View File

@ -0,0 +1,3 @@
import ScoreEvaluationTable from './ScoreEvaluationTable';
export default ScoreEvaluationTable;

View File

@ -35,22 +35,3 @@ export const ApprovalResultColor = {
[ApprovalResult.APPROVED]: 'green',
[ApprovalResult.REJECTED]: 'red',
};
// 导入评价等级
import { EvaluateLevel, EvaluateLevelText, EvaluateLevelColor } from './supplierTemplateDict';
// 重新导出评价等级
export { EvaluateLevel, EvaluateLevelText, EvaluateLevelColor };
// 评价分数对应等级
export const getEvaluateLevel = (score: number): string => {
if (score >= 90) {
return EvaluateLevel.EXCELLENT;
} else if (score >= 80) {
return EvaluateLevel.GOOD;
} else if (score >= 70) {
return EvaluateLevel.AVERAGE;
} else {
return EvaluateLevel.POOR;
}
};

View File

@ -31,14 +31,6 @@ export const TemplateStatusColor = {
[TemplateStatus.DISABLED]: 'red',
};
// 评价等级
export const EvaluateLevel = {
EXCELLENT: 'excellent', // 优秀
GOOD: 'good', // 良好
AVERAGE: 'average', // 一般
POOR: 'poor', // 较差
};
// 是否设置星号项
export const StarLevel = {
NO: '0', // 否
@ -50,20 +42,6 @@ export const StarLevelText = {
[StarLevel.YES]: '是',
};
export const EvaluateLevelText = {
[EvaluateLevel.EXCELLENT]: 'A',
[EvaluateLevel.GOOD]: 'B',
[EvaluateLevel.AVERAGE]: 'C',
[EvaluateLevel.POOR]: 'D',
};
export const EvaluateLevelColor = {
[EvaluateLevel.EXCELLENT]: 'green',
[EvaluateLevel.GOOD]: 'blue',
[EvaluateLevel.AVERAGE]: 'orange',
[EvaluateLevel.POOR]: 'red',
};
// 指标添加选项
export enum IndicatorAddOption {
CAN_ADD = '0',

View File

@ -1,13 +1,24 @@
import login from './en-US/login';
import register from './en-US/register';
import menu from './en-US/menu';
import workbench from './en-US/workbench';
import globalModal from './en-US/globalModal';
import login from './en-US/login';
import menu from './en-US/menu';
import register from './en-US/register';
import workbench from './en-US/workbench';
import supplierEvaluateRuleManage from './en-US/supplierEvaluateRuleManage';
export default {
...login,
...register,
...menu,
...workbench,
'navBar.lang': 'Languages',
'layout.user.link.help': 'Help',
'layout.user.link.privacy': 'Privacy',
'layout.user.link.terms': 'Terms',
'app.home.introduce': 'introduce',
'app.forms.basic.title': 'Basic form',
'app.forms.basic.description':
'Form pages are used to collect or verify information to users, and basic forms are common in scenarios where there are fewer data items.',
'登录/注册': 'Login/Register',
...globalModal,
...login,
...menu,
...register,
...workbench,
...supplierEvaluateRuleManage,
};

View File

@ -6,6 +6,7 @@ export default {
'menu.模板管理': 'Template Management',
'menu.模板管理新增': 'Add Template',
'menu.模板管理详情': 'Template Detail',
'menu.评价规则管理': 'Evaluation Rule Management',
'menu.任务管理': 'Task Management',
'menu.任务管理新增': 'Add Task',
'menu.评价打分': 'Evaluation Scoring',
@ -22,7 +23,7 @@ export default {
'menu.年审任务管理': 'Annual Review Task Management',
'menu.年度查询': 'Annual Query',
'menu.年审结果': 'Annual Review Results',
//供应商
'menu.admit': 'admit',
'menu.dict': 'dict',

View File

@ -0,0 +1,52 @@
export default {
'supplierEvaluateRuleManage.title': 'Evaluation Rule Management',
'supplierEvaluateRuleManage.add': 'Add',
'supplierEvaluateRuleManage.edit': 'Edit',
'supplierEvaluateRuleManage.delete': 'Delete',
'supplierEvaluateRuleManage.confirm': 'Confirm',
'supplierEvaluateRuleManage.cancel': 'Cancel',
'supplierEvaluateRuleManage.submit': 'Submit',
// 表格列名
'supplierEvaluateRuleManage.column.index': 'No.',
'supplierEvaluateRuleManage.column.levelName': 'Level Name',
'supplierEvaluateRuleManage.column.ratingName': 'Rating Name',
'supplierEvaluateRuleManage.column.scoreRange': 'Score Range',
'supplierEvaluateRuleManage.column.remark': 'Remark',
'supplierEvaluateRuleManage.column.action': 'Action',
// 表单字段
'supplierEvaluateRuleManage.form.levelName': 'Level Name',
'supplierEvaluateRuleManage.form.levelName.placeholder': 'Please enter level name, such as A, B, C, etc.',
'supplierEvaluateRuleManage.form.levelName.required': 'Please enter level name',
'supplierEvaluateRuleManage.form.ratingName': 'Rating Name',
'supplierEvaluateRuleManage.form.ratingName.placeholder': 'Please enter rating name, such as Excellent Supplier, Good Supplier, etc.',
'supplierEvaluateRuleManage.form.ratingName.required': 'Please enter rating name',
'supplierEvaluateRuleManage.form.beginValue': 'Start Value',
'supplierEvaluateRuleManage.form.beginValue.placeholder': 'Please enter start value',
'supplierEvaluateRuleManage.form.beginValue.required': 'Please enter start value',
'supplierEvaluateRuleManage.form.beginValue.integer': 'Please enter a positive integer',
'supplierEvaluateRuleManage.form.endValue': 'End Value',
'supplierEvaluateRuleManage.form.endValue.placeholder': 'Please enter end value',
'supplierEvaluateRuleManage.form.endValue.required': 'Please enter end value',
'supplierEvaluateRuleManage.form.endValue.integer': 'Please enter a positive integer',
'supplierEvaluateRuleManage.form.endValue.greater': 'End value must be greater than start value',
'supplierEvaluateRuleManage.form.remark': 'Remark',
'supplierEvaluateRuleManage.form.remark.placeholder': 'Please enter remarks',
// 模态框标题
'supplierEvaluateRuleManage.modal.add': 'Add Evaluation Rule',
'supplierEvaluateRuleManage.modal.edit': 'Edit Evaluation Rule',
'supplierEvaluateRuleManage.modal.delete': 'Confirm Delete',
'supplierEvaluateRuleManage.modal.delete.content': 'Are you sure to delete rule "{levelName}"?',
// 消息提示
'supplierEvaluateRuleManage.message.getList.error': 'Failed to get evaluation rule list',
'supplierEvaluateRuleManage.message.getDetail.error': 'Failed to get evaluation rule detail',
'supplierEvaluateRuleManage.message.add.success': 'Successfully added evaluation rule',
'supplierEvaluateRuleManage.message.add.error': 'Failed to add evaluation rule',
'supplierEvaluateRuleManage.message.update.success': 'Successfully updated evaluation rule',
'supplierEvaluateRuleManage.message.update.error': 'Failed to update evaluation rule',
'supplierEvaluateRuleManage.message.delete.success': 'Successfully deleted rule: {levelName}',
'supplierEvaluateRuleManage.message.delete.error': 'Failed to delete evaluation rule',
};

View File

@ -1,12 +1,24 @@
import login from './zh-CN/login';
import register from './zh-CN/register';
import menu from './zh-CN/menu';
import workbench from './zh-CN/workbench';
import globalModal from './zh-CN/globalModal';
import login from './zh-CN/login';
import menu from './zh-CN/menu';
import register from './zh-CN/register';
import workbench from './zh-CN/workbench';
import supplierEvaluateRuleManage from './zh-CN/supplierEvaluateRuleManage';
export default {
...login,
...register,
...menu,
...workbench,
'navBar.lang': '语言',
'layout.user.link.help': '帮助',
'layout.user.link.privacy': '隐私',
'layout.user.link.terms': '条款',
'app.home.introduce': '介绍',
'app.forms.basic.title': '基础表单',
'app.forms.basic.description':
'表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。',
'登录/注册': '登录/注册',
...globalModal,
...login,
...menu,
...register,
...workbench,
...supplierEvaluateRuleManage,
};

View File

@ -6,6 +6,7 @@ export default {
'menu.模板管理': '模板管理',
'menu.模板管理新增': '模板管理新增',
'menu.模板管理详情': '模板管理详情',
'menu.评价规则管理': '评价规则管理',
'menu.任务管理': '任务管理',
'menu.任务管理新增': '任务管理新增',
'menu.评价打分': '评价打分',
@ -23,7 +24,7 @@ export default {
'menu.年度查询': '年度查询',
'menu.年审结果': '年审结果',
//供应商
'menu.admit': '供应商准入审批',
'menu.dict': '字典',

View File

@ -0,0 +1,52 @@
export default {
'supplierEvaluateRuleManage.title': '评价规则管理',
'supplierEvaluateRuleManage.add': '新增',
'supplierEvaluateRuleManage.edit': '编辑',
'supplierEvaluateRuleManage.delete': '删除',
'supplierEvaluateRuleManage.confirm': '确认',
'supplierEvaluateRuleManage.cancel': '取消',
'supplierEvaluateRuleManage.submit': '提交',
// 表格列名
'supplierEvaluateRuleManage.column.index': '序号',
'supplierEvaluateRuleManage.column.levelName': '等级名称',
'supplierEvaluateRuleManage.column.ratingName': '评级名称',
'supplierEvaluateRuleManage.column.scoreRange': '分数区间',
'supplierEvaluateRuleManage.column.remark': '备注',
'supplierEvaluateRuleManage.column.action': '操作',
// 表单字段
'supplierEvaluateRuleManage.form.levelName': '等级名称',
'supplierEvaluateRuleManage.form.levelName.placeholder': '请输入等级名称如A、B、C等',
'supplierEvaluateRuleManage.form.levelName.required': '请输入等级名称',
'supplierEvaluateRuleManage.form.ratingName': '评级名称',
'supplierEvaluateRuleManage.form.ratingName.placeholder': '请输入评级名称,如优秀供应商、良好供应商等',
'supplierEvaluateRuleManage.form.ratingName.required': '请输入评级名称',
'supplierEvaluateRuleManage.form.beginValue': '起始分值',
'supplierEvaluateRuleManage.form.beginValue.placeholder': '请输入起始分值',
'supplierEvaluateRuleManage.form.beginValue.required': '请输入起始分值',
'supplierEvaluateRuleManage.form.beginValue.integer': '请输入正整数',
'supplierEvaluateRuleManage.form.endValue': '结束分值',
'supplierEvaluateRuleManage.form.endValue.placeholder': '请输入结束分值',
'supplierEvaluateRuleManage.form.endValue.required': '请输入结束分值',
'supplierEvaluateRuleManage.form.endValue.integer': '请输入正整数',
'supplierEvaluateRuleManage.form.endValue.greater': '结束分值必须大于起始分值',
'supplierEvaluateRuleManage.form.remark': '备注',
'supplierEvaluateRuleManage.form.remark.placeholder': '请输入备注信息',
// 模态框标题
'supplierEvaluateRuleManage.modal.add': '新增评价规则',
'supplierEvaluateRuleManage.modal.edit': '编辑评价规则',
'supplierEvaluateRuleManage.modal.delete': '确认删除',
'supplierEvaluateRuleManage.modal.delete.content': '确定要删除规则"{levelName}"吗?',
// 消息提示
'supplierEvaluateRuleManage.message.getList.error': '获取评价规则列表失败',
'supplierEvaluateRuleManage.message.getDetail.error': '获取评价规则详情失败',
'supplierEvaluateRuleManage.message.add.success': '新增评价规则成功',
'supplierEvaluateRuleManage.message.add.error': '新增评价规则失败',
'supplierEvaluateRuleManage.message.update.success': '更新评价规则成功',
'supplierEvaluateRuleManage.message.update.error': '更新评价规则失败',
'supplierEvaluateRuleManage.message.delete.success': '成功删除规则: {levelName}',
'supplierEvaluateRuleManage.message.delete.error': '删除评价规则失败',
};

View File

@ -1,17 +0,0 @@
import React from 'react';
const LinkComponent: React.FC = () => {
return (
<div className="link">
<div></div>
<div className="flex">
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
</div>
</div>
);
};
export default LinkComponent;

View File

@ -1,244 +1,7 @@
import React, { useState } from 'react';
import { Card, Row, Col, Tabs, Table } from 'antd';
import { useIntl, Link } from 'umi';
import './index.less';
import IconFont from '@/components/IconFont/IconFont';
import LinkComponent from './Link';
const IndexPage: React.FC = () => {
const intl = useIntl();
const [noticeLoading, setNoticeLoading] = useState(false);
const [noticeList, setNoticeList] = useState([
{
title: 'CA使用通知',
id: '1',
content: '系统将于2022年5月27日期开始对全流程使用CA服务届时全部投标供应商需办理CA。',
},
{
title: '5月27日系统优化升级通知',
id: '2',
content:
'系统将于2022年5月27日周五22:00--2022年5月28日周六6:00进行系统优化升级届时系统将暂停服务。',
},
{
title: '测试标题123123',
id: '3',
content: '测试内容124145',
},
{
title: '测试标题45435',
id: '4',
content: '测试内容6666',
},
]);
const tabList = [
{
key: '1',
label: intl.formatMessage({ id: '采购需求公示' }),
},
{
key: '2',
label: intl.formatMessage({ id: '招标采购公告' }),
},
{
key: '3',
label: intl.formatMessage({ id: '非招标采购公告' }),
},
{
key: '4',
label: intl.formatMessage({ id: '资格预审公告' }),
},
{
key: '5',
label: intl.formatMessage({ id: '招募公告' }),
},
{
key: '6',
label: intl.formatMessage({ id: '变更公告' }),
},
{
key: '7',
label: intl.formatMessage({ id: '中标(中选)候选人公示' }),
},
{
key: '8',
label: intl.formatMessage({ id: '中标(中选)结果公示' }),
},
{
key: '9',
label: intl.formatMessage({ id: '采购失败(流标)公告' }),
},
];
//tab 切换事件
const tabChange = (key: string) => {
console.log(key);
};
const [tableLoading, setTableLoading] = useState(false);
const dataSource = [
{
key: '1',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
];
const columns = [
{
title: '项目所在地',
dataIndex: 'address',
key: 'address',
},
{
title: '公告标题',
dataIndex: 'title',
key: 'title',
render: (text: string, record) => (
<Link
to={{
pathname: '/announce/announceInfo',
search: '?id=' + record.id,
}}
>
{text}
</Link>
),
},
{
title: '发布时间',
dataIndex: 'date',
key: 'date',
},
{
title: '文件购买截止时间',
dataIndex: 'lastDate',
key: 'lastDate',
render: (text: string) => <span className="lastDate">{text}</span>,
},
];
return (
<div>
{/* 通知列表 */}
<Row gutter={20}>
{noticeList.map((item) => (
<Col span={6} key={item.id}>
<Card
title={item.title}
loading={noticeLoading}
hoverable
className="card"
bodyStyle={{ padding: 10 }}
extra={
<Link
to={{
pathname: '/notice/noticeInfo',
search: '?id=' + item.id,
}}
>
{intl.formatMessage({ id: '查看' })}
</Link>
}
>
<p className="cardContent">{item.content}</p>
</Card>
</Col>
))}
</Row>
<Tabs onChange={tabChange}>
{tabList.map((item) => (
<Tabs.TabPane tab={item.label} key={item.key} />
))}
</Tabs>
<Table loading={tableLoading} dataSource={dataSource} columns={columns} pagination={false} />
<div className="tableLoadMore">
<Link
to={{
pathname: '/announce',
}}
>
{intl.formatMessage({ id: '加载更多' })}
</Link>
</div>
<Row style={{ marginTop: '20px', backgroundColor: '#fff' }}>
<Col span={12}>
<div className="blockTitle"></div>
<img src="" alt="" />
<div className="questionItem">
<IconFont type="icon-dizhi" className="icon" />
173
</div>
<div className="questionItem">
<IconFont type="icon-dianhua" className="icon" />
17676373746
</div>
<div className="questionItem">
<IconFont type="icon-youxiang" className="icon" />
i723648723@383.com
</div>
</Col>
<Col span={12}>
<div className="blockTitle">CA服务</div>
<Row>
<Col span={6} offset={6}>
<span>CA办理</span>
</Col>
<Col span={6}>
<span>CA客服</span>
</Col>
</Row>
<div className="blockTitle"></div>
<p style={{ marginTop: 20 }}>客服1: 400-300-9989</p>
<p>客服1: 400-300-9989</p>
<p>客服1: 400-300-9989</p>
<p>客服1: 400-300-9989</p>
</Col>
</Row>
<div>
<LinkComponent />
</div>
</div>
);
return <div></div>;
};
export default IndexPage;

View File

@ -1,221 +0,0 @@
import React from 'react';
import { Table, Progress, Typography, Card, Tag } from 'antd';
import styles from './components.less';
const { Title, Text } = Typography;
interface GeneralEvaluationProps {
supplierName?: string;
}
const GeneralEvaluation: React.FC<GeneralEvaluationProps> = ({ supplierName }) => {
// 评价数据
const evaluationData = [
{
key: '1',
firstIndex: '基本情况(base case)',
firstDescription: '企业基本资质与存续状态证明',
firstScore: 4,
secondIndex: '资质文件',
secondScore: 1,
averageScore: 3,
rowSpan: 2,
},
{
key: '2',
firstIndex: '基本情况(base case)',
firstDescription: '企业基本资质与存续状态证明',
firstScore: 4,
secondIndex: 'XXX',
secondScore: 3,
averageScore: 1,
rowSpan: 0, // 设为0表示不显示
},
{
key: '3',
firstIndex: '成本(cost)',
firstDescription: '商品与服务的总拥有成本',
firstScore: 7,
secondIndex: 'XXX',
secondScore: 7,
averageScore: 6.5,
rowSpan: 1,
},
{
key: '4',
firstIndex: '创新(innovate)',
firstDescription: '为公司提供竞争优势,提高商业价值而持续提供创新性建议及解决方案',
firstScore: 20,
secondIndex: 'XXX',
secondScore: 20,
averageScore: 18.5,
rowSpan: 1,
},
{
key: '5',
firstIndex: '服务 (service)',
firstDescription: '为满足公司商业需求而提供的服务与支持',
firstScore: 10,
secondIndex: 'XXX',
secondScore: 10,
averageScore: 10,
rowSpan: 1,
},
{
key: '6',
firstIndex: '质量(quality)',
firstDescription: '提供满足需求(规格)的产品与服务',
firstScore: 25,
secondIndex: 'XXX',
secondScore: 25,
averageScore: 24,
rowSpan: 1,
},
{
key: '7',
firstIndex: '绿色(environment protection)',
firstDescription: '优秀的交付能力及与之相关的灵活性',
firstScore: 25,
secondIndex: 'XXX',
secondScore: 25,
averageScore: 24,
rowSpan: 1,
},
{
key: '8',
firstIndex: '安全(safety)',
firstDescription: '产品质量安全、环境保护、风险防控及商业道德约束',
firstScore: 6,
secondIndex: 'XXX',
secondScore: 6,
averageScore: 5,
rowSpan: 1,
},
{
key: '9',
firstIndex: '廉洁(integrity)',
firstDescription: '商业道德约束',
firstScore: 3,
secondIndex: '商业贿赂与道德风险',
secondScore: 3,
averageScore: 3,
rowSpan: 1,
},
{
key: '10',
firstIndex: '合计',
firstDescription: '',
firstScore: 100,
secondIndex: '',
secondScore: 100,
averageScore: 95,
rowSpan: 1,
},
];
const columns = [
{
title: '',
dataIndex: 'index',
key: 'index',
width: 50,
render: (text: string, record: any, index: number) => index + 1,
},
{
title: '一级指标',
children: [
{
title: '*基本指标',
dataIndex: 'firstIndex',
key: 'firstIndex',
width: 150,
render: (text: string, record: any, index: number) => {
return {
children: text,
props: {
rowSpan: record.rowSpan,
},
};
},
},
{
title: '*指标说明',
dataIndex: 'firstDescription',
key: 'firstDescription',
width: 220,
render: (text: string, record: any) => {
return {
children: text,
props: {
rowSpan: record.rowSpan,
},
};
},
},
{
title: '分值',
dataIndex: 'firstScore',
key: 'firstScore',
width: 80,
render: (text: number, record: any) => {
return {
children: text,
props: {
rowSpan: record.rowSpan,
},
};
},
},
],
},
{
title: '二级指标',
children: [
{
title: '*细分指标',
dataIndex: 'secondIndex',
key: 'secondIndex',
width: 180,
},
{
title: '分值',
dataIndex: 'secondScore',
key: 'secondScore',
width: 80,
},
],
},
{
title: '平均分',
dataIndex: 'averageScore',
key: 'averageScore',
width: 80,
render: (score: number) => (
<span className={score < 60 ? styles.lowScore : ''}>
{score}
</span>
),
},
];
// 计算总分
const totalScore = evaluationData[evaluationData.length - 1].averageScore;
const totalPossibleScore = evaluationData[evaluationData.length - 1].firstScore;
const scorePercentage = (totalScore / totalPossibleScore) * 100;
return (
<div className={styles.evaluationContainer}>
<Table
columns={columns}
dataSource={evaluationData}
pagination={false}
className={styles.scoreTable}
bordered
size="middle"
/>
</div>
);
};
export default GeneralEvaluation;

View File

@ -1,265 +0,0 @@
import React from 'react';
import { Table, Progress, Typography, Card, Tag } from 'antd';
import styles from './components.less';
const { Title, Text } = Typography;
interface TechnicalEvaluationProps {
supplierName?: string;
}
const TechnicalEvaluation: React.FC<TechnicalEvaluationProps> = ({ supplierName }) => {
// 评价数据
const evaluationData = [
{
key: '1',
firstIndex: '技术实力',
firstDescription: '技术团队规模与研发能力',
firstScore: 20,
secondIndex: '研发团队规模',
secondScore: 10,
averageScore: 9,
rowSpan: 2,
},
{
key: '2',
firstIndex: '技术实力',
firstDescription: '技术团队规模与研发能力',
firstScore: 20,
secondIndex: '技术创新能力',
secondScore: 10,
averageScore: 8,
rowSpan: 0, // 设为0表示不显示
},
{
key: '3',
firstIndex: '产品性能',
firstDescription: '产品的技术指标与性能表现',
firstScore: 25,
secondIndex: '核心性能指标',
secondScore: 15,
averageScore: 14,
rowSpan: 2,
},
{
key: '4',
firstIndex: '产品性能',
firstDescription: '产品的技术指标与性能表现',
firstScore: 25,
secondIndex: '稳定性与可靠性',
secondScore: 10,
averageScore: 9.5,
rowSpan: 0,
},
{
key: '5',
firstIndex: '技术支持',
firstDescription: '提供的技术服务与支持能力',
firstScore: 15,
secondIndex: '响应速度',
secondScore: 8,
averageScore: 7.5,
rowSpan: 2,
},
{
key: '6',
firstIndex: '技术支持',
firstDescription: '提供的技术服务与支持能力',
firstScore: 15,
secondIndex: '问题解决能力',
secondScore: 7,
averageScore: 6.5,
rowSpan: 0,
},
{
key: '7',
firstIndex: '技术文档',
firstDescription: '技术文档的完整性与准确性',
firstScore: 10,
secondIndex: '文档完整性',
secondScore: 5,
averageScore: 4.5,
rowSpan: 2,
},
{
key: '8',
firstIndex: '技术文档',
firstDescription: '技术文档的完整性与准确性',
firstScore: 10,
secondIndex: '文档准确性',
secondScore: 5,
averageScore: 4,
rowSpan: 0,
},
{
key: '9',
firstIndex: '技术培训',
firstDescription: '提供的技术培训与知识转移',
firstScore: 15,
secondIndex: '培训质量',
secondScore: 8,
averageScore: 7,
rowSpan: 2,
},
{
key: '10',
firstIndex: '技术培训',
firstDescription: '提供的技术培训与知识转移',
firstScore: 15,
secondIndex: '培训频率',
secondScore: 7,
averageScore: 6,
rowSpan: 0,
},
{
key: '11',
firstIndex: '兼容性',
firstDescription: '与现有系统的兼容性',
firstScore: 15,
secondIndex: '系统兼容性评估',
secondScore: 15,
averageScore: 13.5,
rowSpan: 1,
},
{
key: '12',
firstIndex: '合计',
firstDescription: '',
firstScore: 100,
secondIndex: '',
secondScore: 100,
averageScore: 89.5,
rowSpan: 1,
},
];
const columns = [
{
title: '',
dataIndex: 'index',
key: 'index',
width: 50,
render: (text: string, record: any, index: number) => index + 1,
},
{
title: '一级指标',
children: [
{
title: '*基本指标',
dataIndex: 'firstIndex',
key: 'firstIndex',
width: 150,
className: styles.requiredColumn,
render: (text: string, record: any, index: number) => {
return {
children: text,
props: {
rowSpan: record.rowSpan,
},
};
},
},
{
title: '*指标说明',
dataIndex: 'firstDescription',
key: 'firstDescription',
width: 220,
className: styles.requiredColumn,
render: (text: string, record: any) => {
return {
children: text,
props: {
rowSpan: record.rowSpan,
},
};
},
},
{
title: '分值',
dataIndex: 'firstScore',
key: 'firstScore',
width: 80,
render: (text: number, record: any) => {
return {
children: text,
props: {
rowSpan: record.rowSpan,
},
};
},
},
],
},
{
title: '二级指标',
children: [
{
title: '*细分指标',
dataIndex: 'secondIndex',
key: 'secondIndex',
width: 180,
className: styles.requiredColumn,
},
{
title: '分值',
dataIndex: 'secondScore',
key: 'secondScore',
width: 80,
},
],
},
{
title: '平均分',
dataIndex: 'averageScore',
key: 'averageScore',
width: 80,
render: (score: number) => (
<span className={score < 60 ? styles.lowScore : ''}>
{score}
</span>
),
},
];
// 计算总分
const totalScore = evaluationData[evaluationData.length - 1].averageScore;
const totalPossibleScore = evaluationData[evaluationData.length - 1].firstScore;
const scorePercentage = (totalScore / totalPossibleScore) * 100;
return (
<div className={styles.evaluationContainer}>
<Card className={styles.summaryCard}>
<div className={styles.scoreSummary}>
<div className={styles.scoreCircle}>
<Progress
type="circle"
percent={scorePercentage}
format={() => `${totalScore}`}
width={80}
strokeColor={{
'0%': '#108ee9',
'100%': '#87d068',
}}
/>
</div>
<div className={styles.scoreInfo}>
<Title level={4}></Title>
<Text type="secondary">: {totalPossibleScore}</Text>
{supplierName && <Text type="secondary">: {supplierName}</Text>}
</div>
</div>
</Card>
<Table
columns={columns}
dataSource={evaluationData}
pagination={false}
className={styles.scoreTable}
bordered
size="middle"
/>
</div>
);
};
export default TechnicalEvaluation;

View File

@ -1,80 +0,0 @@
.evaluationContainer {
margin-top: 16px;
}
.summaryCard {
margin-bottom: 16px;
}
.scoreSummary {
display: flex;
align-items: center;
}
.scoreCircle {
margin-right: 24px;
}
.scoreInfo {
display: flex;
flex-direction: column;
justify-content: center;
h4 {
margin-bottom: 4px;
}
}
.scoreCell {
display: flex;
flex-direction: column;
span {
margin-bottom: 4px;
}
}
.scoreTable {
margin-top: 16px;
:global {
.ant-table-thead > tr > th {
background-color: #f5f5f5;
text-align: center;
font-weight: 500;
}
.ant-table-tbody > tr > td {
text-align: center;
vertical-align: middle;
}
}
}
/* 必填列样式 */
.requiredColumn {
position: relative;
&::before {
content: '*';
color: #ff4d4f;
position: absolute;
left: 8px;
top: 50%;
transform: translateY(-50%);
}
}
/* 低分警示 */
.lowScore {
color: #ff4d4f;
font-weight: 500;
}
/* 表格嵌套表头样式 */
:global {
.ant-table-thead > tr > th.ant-table-cell-fix-left,
.ant-table-thead > tr > th.ant-table-cell-fix-right {
background-color: #f5f5f5;
}
}

View File

@ -188,11 +188,25 @@ const SupplierEvaluateResult: React.FC = () => {
</Tooltip>
),
},
{
title: '评价品类',
dataIndex: 'category',
key: 'category',
width: 120,
ellipsis: {
showTitle: false,
},
render: (text: string) => (
<Tooltip placement="topLeft" title={text || '未指定'}>
{text || '未指定'}
</Tooltip>
),
},
{
title: '发起单位',
dataIndex: 'tenantName',
key: 'tenantName',
width: 200,
dataIndex: 'deptName',
key: 'deptName',
width: 180,
ellipsis: {
showTitle: false,
},

View File

@ -1,202 +1,145 @@
// 评价结果详情
import React, { useState, useEffect } from 'react';
import { Card, Form, Button, Descriptions, Divider, Row, Col, Tabs, message } from 'antd';
import { Card, Button, message, Typography } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { history, useLocation } from 'umi';
import { EvaluateLevel, EvaluateLevelText } from '@/dicts/supplierTemplateDict';
import GeneralEvaluation from './components/GeneralEvaluation';
import TechnicalEvaluation from './components/TechnicalEvaluation';
import ScoreEvaluationTable from '@/components/ScoreEvaluationTable';
import styles from './supplierEvaluateResult.less';
import { getIndicator } from '@/servers/api/supplierEvaluate';
const { TabPane } = Tabs;
const { Title } = Typography;
// 组件使用默认的接口定义
// 评价打分详情数据接口
interface IndicatorDetailData {
category: string;
name: string;
taskIndicatorVo: {
baseIndicator: string;
indicatorDesc: string;
score: string;
subIndicator: {
id: string;
remark: string | null;
scoreNum: string | null;
starIndicator: string;
stId: string;
subIndicator: string;
subScore: string;
}[];
}[];
}
const SupplierEvaluateResultByZb: React.FC = () => {
const location = useLocation<{ record: any }>();
const location = useLocation<{
record: API.EvaluateScoreIndicator;
parentRecord: API.EvaluateTaskRecord;
supplierRecord: API.EvaluateSupplierRecord;
scoreDetail: API.EvaluateScoreData;
}>();
const [loading, setLoading] = useState<boolean>(false);
const [scoreRecord, setScoreRecord] = useState<any>(null);
const [evaluationData, setEvaluationData] = useState<{
general: any[];
technical: any[];
}>({
general: [],
technical: [],
});
// 模拟获取评价详情数据
const fetchEvaluationData = (record: any) => {
setLoading(true);
try {
// 模拟API请求
setTimeout(() => {
// 模拟通用评价数据
const generalData = [
{
id: '1',
firstIndex: '质量管理',
firstDescription: '供应商质量管理体系评价',
secondIndex: '质量管理体系认证',
secondDescription: '是否通过ISO9001认证',
score: 9,
weight: 0.1,
weightedScore: 0.9,
comment: '已通过ISO9001认证证书有效',
},
{
id: '2',
firstIndex: '质量管理',
firstDescription: '供应商质量管理体系评价',
secondIndex: '质量控制流程',
secondDescription: '是否建立完善的质量控制流程',
score: 8,
weight: 0.1,
weightedScore: 0.8,
comment: '质量控制流程完善,但执行记录不够完整',
},
{
id: '3',
firstIndex: '交付能力',
firstDescription: '供应商交付能力评价',
secondIndex: '准时交付率',
secondDescription: '过去一年准时交付率评价',
score: 9.5,
weight: 0.15,
weightedScore: 1.425,
comment: '准时交付率98%,表现优秀',
},
];
// 模拟技术评价数据
const technicalData = [
{
id: '1',
firstIndex: '技术能力',
firstDescription: '供应商技术研发能力评价',
secondIndex: '研发投入',
secondDescription: '研发投入占营业额比例',
score: 8.5,
weight: 0.1,
weightedScore: 0.85,
comment: '研发投入占营业额5%,符合行业平均水平',
},
{
id: '2',
firstIndex: '技术能力',
firstDescription: '供应商技术研发能力评价',
secondIndex: '专利数量',
secondDescription: '拥有专利数量评价',
score: 9,
weight: 0.05,
weightedScore: 0.45,
comment: '拥有15项有效专利其中发明专利5项',
},
{
id: '3',
firstIndex: '设备设施',
firstDescription: '供应商设备设施评价',
secondIndex: '设备先进性',
secondDescription: '生产设备先进程度评价',
score: 8,
weight: 0.1,
weightedScore: 0.8,
comment: '主要生产设备较为先进,但部分设备需要更新',
},
];
setEvaluationData({
general: generalData,
technical: technicalData,
});
setLoading(false);
}, 500);
} catch (error) {
console.error('获取评价详情数据失败:', error);
message.error('获取评价详情数据失败');
setLoading(false);
}
};
const [scoreRecord, setScoreRecord] = useState<API.EvaluateScoreIndicator | null>(null);
const [parentRecord, setParentRecord] = useState<API.EvaluateTaskRecord | null>(null);
const [supplierRecord, setSupplierRecord] = useState<API.EvaluateSupplierRecord | null>(null);
const [indicatorDetail, setIndicatorDetail] = useState<IndicatorDetailData | null>(null);
// 获取上级页面传递的数据
useEffect(() => {
if (location.state?.record) {
setScoreRecord(location.state.record);
// 模拟获取评价详情数据
fetchEvaluationData(location.state.record);
}
if (location.state?.parentRecord) {
setParentRecord(location.state.parentRecord);
}
if (location.state?.supplierRecord) {
setSupplierRecord(location.state.supplierRecord);
}
if (location.state?.scoreDetail) {
// 如果有上级页面传递的评分明细数据,暂存下来
// 稍后我们仍然会通过API获取最新数据
}
}, [location]);
// 获取评价打分详情数据
const fetchIndicatorDetail = async () => {
if (!scoreRecord?.id) {
message.error('缺少评价记录ID无法获取数据');
return;
}
setLoading(true);
try {
const response = await getIndicator(scoreRecord.id);
if (response.data && response.success) {
setIndicatorDetail(response.data);
} else {
message.error(response.message || '获取评价打分详情失败');
}
} catch (error) {
console.error('获取评价打分详情失败:', error);
message.error('获取评价打分详情失败');
} finally {
setLoading(false);
}
};
// 监听scoreRecord变化获取评价详情数据
useEffect(() => {
if (scoreRecord?.id) {
fetchIndicatorDetail();
}
}, [scoreRecord]);
// 返回上一页
const handleBack = () => {
history.goBack();
};
// 计算总得分
const calculateTotalScore = () => {
let totalScore = 0;
let totalWeight = 0;
// 将API数据转换为ScoreEvaluationTable组件所需的格式
const formatDataForScoreTable = () => {
if (!indicatorDetail?.taskIndicatorVo) return [];
// 计算通用评价得分
evaluationData.general.forEach((item: any) => {
totalScore += item.weightedScore;
totalWeight += item.weight;
return indicatorDetail.taskIndicatorVo.map(indicator => {
return {
baseIndicator: indicator.baseIndicator,
descIndicator: indicator.indicatorDesc,
score: indicator.score,
indicatorNdList: indicator.subIndicator?.map(subItem => {
return {
subIndicator: subItem.subIndicator,
score: subItem.subScore,
isStar: subItem.starIndicator,
id: subItem.id,
actualScore: subItem.scoreNum || '',
remark: subItem.remark || ''
};
}) || []
};
});
// 计算技术评价得分
evaluationData.technical.forEach((item: any) => {
totalScore += item.weightedScore;
totalWeight += item.weight;
});
// 如果权重总和不为0则计算加权平均分
if (totalWeight > 0) {
return (totalScore / totalWeight).toFixed(2);
}
return '0.00';
};
// 获取评价等级
const getEvaluateLevel = (score: number) => {
if (score >= 90) {
return EvaluateLevelText[EvaluateLevel.EXCELLENT];
} else if (score >= 80) {
return EvaluateLevelText[EvaluateLevel.GOOD];
} else if (score >= 70) {
return EvaluateLevelText[EvaluateLevel.AVERAGE];
} else {
return EvaluateLevelText[EvaluateLevel.POOR];
}
};
if (!scoreRecord) {
if (loading && !indicatorDetail) {
return <div className="common-container">...</div>;
}
const supplierName = supplierRecord?.supplierName || indicatorDetail?.name || '供应商';
return (
<div className="common-container">
<div className="action-row">
<div className="filter-action-row">
<Title level={4} className={styles.pageTitle}>
{supplierName} -
</Title>
<Button type="link" icon={<ArrowLeftOutlined />} onClick={handleBack}>
</Button>
</div>
<Card title="评价基本信息" bordered={false} className={styles.infoCard}>
<Descriptions column={3}>
<Descriptions.Item label="供应商名称">{scoreRecord.supplierName}</Descriptions.Item>
<Descriptions.Item label="品类">{scoreRecord.category}</Descriptions.Item>
<Descriptions.Item label="评价单位">{scoreRecord.evaluateUnit}</Descriptions.Item>
<Descriptions.Item label="评价人员">{scoreRecord.evaluator}</Descriptions.Item>
<Descriptions.Item label="评价时间">{scoreRecord.evaluateTime}</Descriptions.Item>
<Descriptions.Item label="评价得分">{scoreRecord.score}</Descriptions.Item>
<Descriptions.Item label="评价等级">
{getEvaluateLevel(scoreRecord.score)}
</Descriptions.Item>
</Descriptions>
</Card>
<Card title="评价详情" bordered={false} className={styles.detailCard}>
<GeneralEvaluation supplierName={scoreRecord.supplierName} />
<Card title="评价指标详情" bordered={false} className={styles.detailCard}>
<ScoreEvaluationTable
value={formatDataForScoreTable()}
isDetail={true}
loading={loading}
/>
</Card>
</div>
);

View File

@ -8,33 +8,27 @@ import {
Button,
Table,
Space,
Tag,
TablePaginationConfig,
Modal,
Row,
Col,
Tooltip,
message,
} from 'antd';
import type { TablePaginationConfig } from 'antd';
import {
SearchOutlined,
DeleteOutlined,
ArrowLeftOutlined,
FileTextOutlined,
BarChartOutlined,
} from '@ant-design/icons';
import { history, useLocation } from 'umi';
import moment from 'moment';
import { EvaluateLevel, EvaluateLevelText, EvaluateLevelColor } from '@/dicts/supplierTemplateDict';
import styles from './supplierEvaluateResult.less';
import { getEvaluateSupplierList, getAllEvaluateRules } from '@/servers/api/supplierEvaluate';
const { Option } = Select;
const SupplierEvaluateResultInfo: React.FC = () => {
const location = useLocation<{ record: SupplierEvaluate.EvaluateResultRecord }>();
const location = useLocation<{ record: API.EvaluateTaskRecord }>();
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
const [resultData, setResultData] = useState<SupplierEvaluate.EvaluateResultDetailRecord[]>([]);
const [resultData, setResultData] = useState<API.EvaluateSupplierRecord[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10,
@ -44,10 +38,11 @@ const SupplierEvaluateResultInfo: React.FC = () => {
showTotal: (total) => `${total} 条记录`,
});
const [searchParams, setSearchParams] =
useState<SupplierEvaluate.EvaluateResultDetailSearchParams>({});
const [parentRecord, setParentRecord] = useState<SupplierEvaluate.EvaluateResultRecord | null>(
useState<API.EvaluateSupplierSearchParams>({});
const [parentRecord, setParentRecord] = useState<API.EvaluateTaskRecord | null>(
null,
);
const [evaluateRules, setEvaluateRules] = useState<API.EvaluateRuleItem[]>([]);
// 品类数据
const categoryOptions = [
@ -58,12 +53,6 @@ const SupplierEvaluateResultInfo: React.FC = () => {
{ label: '医药', value: '医药' },
];
// 评价等级选项
const levelOptions = Object.entries(EvaluateLevelText).map(([value, label]) => ({
label,
value,
}));
// 获取上级页面传递的数据
useEffect(() => {
if (location.state?.record) {
@ -71,12 +60,38 @@ const SupplierEvaluateResultInfo: React.FC = () => {
}
}, [location]);
// 模拟获取评价结果详情列表
// 获取评价规则列表
const fetchEvaluateRules = async () => {
try {
const response = await getAllEvaluateRules();
if (response.success && response.data) {
setEvaluateRules(response.data);
} else {
message.error(response.message || '获取评价规则列表失败');
}
} catch (error) {
console.error('获取评价规则列表失败:', error);
message.error('获取评价规则列表失败');
}
};
// 首次加载获取评价规则列表
useEffect(() => {
fetchEvaluateRules();
}, []);
// 获取评价结果详情列表
const fetchResultDetailList = async (
current = 1,
pageSize = 10,
params: SupplierEvaluate.EvaluateResultDetailSearchParams = searchParams,
params: API.EvaluateSupplierSearchParams = searchParams,
) => {
// 确保有评价任务ID
if (!parentRecord?.id) {
message.error('缺少评价任务ID无法获取数据');
return;
}
// 更新搜索参数状态
if (params !== searchParams) {
setSearchParams(params);
@ -84,77 +99,58 @@ const SupplierEvaluateResultInfo: React.FC = () => {
setLoading(true);
try {
// 模拟API请求
setTimeout(() => {
// 模拟数据
const mockData: SupplierEvaluate.EvaluateResultDetailRecord[] = Array.from({
length: 35,
}).map((_, index) => {
const id = `${index + 1}`;
// 构建请求参数
const requestParams: API.EvaluateSupplierRequest = {
basePageRequest: {
pageNo: current,
pageSize: pageSize,
},
evaluateTaskId: parentRecord.id,
};
// 随机选择品类
const categoryIndex = Math.floor(Math.random() * categoryOptions.length);
// 添加搜索条件
if (params.supplierName) {
requestParams.supplierName = params.supplierName;
}
if (params.level) {
requestParams.level = params.level;
}
// 随机生成得分和等级
const score = Math.floor(Math.random() * 40) + 60; // 60-100分
let level;
if (score >= 90) {
level = EvaluateLevel.EXCELLENT;
} else if (score >= 80) {
level = EvaluateLevel.GOOD;
} else if (score >= 70) {
level = EvaluateLevel.AVERAGE;
} else {
level = EvaluateLevel.POOR;
}
// 调用接口获取数据
const response = await getEvaluateSupplierList(requestParams);
if (response.data && response.success) {
const { records, total, current: currentPage, size } = response.data;
return {
id,
key: id,
supplierName: `供应商${index + 1}`,
category: categoryOptions[categoryIndex].value,
score,
level,
};
});
// 处理数据增加表格需要的key属性
const formattedData = records.map(record => ({
...record,
key: record.id,
}));
// 根据搜索条件过滤
let filteredData = [...mockData];
if (params.supplierName) {
filteredData = filteredData.filter((item) =>
item.supplierName.includes(params.supplierName || ''),
);
}
if (params.level) {
filteredData = filteredData.filter((item) => item.level === params.level);
}
// 分页
const startIndex = (current - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedData = filteredData.slice(startIndex, endIndex);
setResultData(paginatedData);
setResultData(formattedData);
setPagination({
...pagination,
current,
pageSize,
total: filteredData.length,
current: currentPage,
pageSize: size,
total,
});
setLoading(false);
}, 500);
} else {
message.error(response.message || '获取评价结果详情列表失败');
}
} catch (error) {
console.error('获取评价结果详情列表失败:', error);
message.error('获取评价结果详情列表失败');
} finally {
setLoading(false);
}
};
// 首次加载获取数据
useEffect(() => {
fetchResultDetailList(pagination.current, pagination.pageSize, {});
}, []);
if (parentRecord?.id) {
fetchResultDetailList(pagination.current, pagination.pageSize, {});
}
}, [parentRecord]);
// 处理表格分页变化
const handleTableChange = (newPagination: TablePaginationConfig) => {
@ -178,31 +174,25 @@ const SupplierEvaluateResultInfo: React.FC = () => {
};
// 查看得分明细
const handleViewScoreDetail = (record: SupplierEvaluate.EvaluateResultDetailRecord) => {
const handleViewScoreDetail = (record: API.EvaluateSupplierRecord) => {
history.push({
pathname: 'supplierEvaluateResultScoreDetail',
state: { record }
state: { record, parentRecord }
});
};
// 查看打分情况
const handleViewScoring = (record: SupplierEvaluate.EvaluateResultDetailRecord) => {
const handleViewScoring = (record: API.EvaluateSupplierRecord) => {
history.push({
pathname: 'supplierEvaluateResultScoreByList',
state: { record }
state: { record, parentRecord }
});
};
// 获取等级标签
const getLevelTag = (level: string) => {
const text = EvaluateLevelText[level as keyof typeof EvaluateLevelText] || '未知等级';
return text;
};
const columns = [
{
title: '序号',
render: (_: any, __: SupplierEvaluate.EvaluateResultDetailRecord, index: number) =>
render: (_: any, __: API.EvaluateSupplierRecord, index: number) =>
(pagination.current! - 1) * pagination.pageSize! + index + 1,
width: 80,
},
@ -228,24 +218,23 @@ const SupplierEvaluateResultInfo: React.FC = () => {
},
{
title: '评价得分',
dataIndex: 'score',
key: 'score',
dataIndex: 'reviewScore',
key: 'reviewScore',
width: 100
},
{
title: '评价等级',
dataIndex: 'level',
key: 'level',
dataIndex: 'levelName',
key: 'levelName',
width: 100,
align: 'center' as const,
render: (level: string) => getLevelTag(level),
align: 'center' as const
},
{
title: '操作',
key: 'action',
width: 180,
align: 'center' as const,
render: (_: unknown, record: SupplierEvaluate.EvaluateResultDetailRecord) => (
render: (_: unknown, record: API.EvaluateSupplierRecord) => (
<Space size="middle">
<Button
type="link"
@ -270,9 +259,9 @@ const SupplierEvaluateResultInfo: React.FC = () => {
</Form.Item>
<Form.Item name="level" label="评价等级">
<Select placeholder="请选择评价等级" allowClear style={{ width: 150 }}>
{levelOptions.map((option) => (
<Option key={option.value} value={option.value}>
{option.label}
{evaluateRules.map((rule) => (
<Option key={rule.id} value={rule.levelName}>
{rule.levelName}
</Option>
))}
</Select>

View File

@ -1,34 +1,58 @@
// 供应商评价结果打分情况
import React, { useState, useEffect } from 'react';
import {
Card,
Form,
Input,
Select,
Button,
Table,
Space,
TablePaginationConfig,
Tooltip,
message,
} from 'antd';
import {
SearchOutlined,
DeleteOutlined,
ArrowLeftOutlined,
EyeOutlined,
} from '@ant-design/icons';
import type { TablePaginationConfig } from 'antd';
import { SearchOutlined, DeleteOutlined, ArrowLeftOutlined } from '@ant-design/icons';
import { history, useLocation } from 'umi';
import { EvaluateLevel, EvaluateLevelText } from '@/dicts/supplierTemplateDict';
import styles from './supplierEvaluateResult.less';
import { getEvaluateScoreList, getAllEvaluateRules } from '@/servers/api/supplierEvaluate';
// 为修复类型问题,定义新的评分数据结构
interface ScoreDataItem {
id: string;
key: string;
name?: string;
supplierName: string;
evaluateTheme: string;
startTime?: string;
endTime?: string;
evaluateTime: string;
status?: string;
statusName?: string;
score: string | number;
suscore?: string | number;
createBy?: string;
createTime?: string;
updateBy?: string;
updateTime?: string;
categoryName?: string; // 品类名称
deptName?: string; // 评价单位
evaluatorName?: string; // 评价人员
[key: string]: any;
}
// 自定义类型用于传递给详情页的数据
interface DetailPageState {
record: ScoreDataItem;
parentRecord: API.EvaluateSupplierRecord | null;
}
const { Option } = Select;
const SupplierEvaluateResultScoreByList: React.FC = () => {
const location = useLocation<{ record: SupplierEvaluate.EvaluateResultDetailRecord }>();
const location = useLocation<{
record: API.EvaluateSupplierRecord;
}>();
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
const [scoreData, setScoreData] = useState<any[]>([]);
const [scoreData, setScoreData] = useState<ScoreDataItem[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10,
@ -37,28 +61,50 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
showQuickJumper: true,
showTotal: (total) => `${total} 条记录`,
});
const [searchParams, setSearchParams] = useState<any>({});
const [supplierRecord, setSupplierRecord] = useState<SupplierEvaluate.EvaluateResultDetailRecord | null>(null);
const [searchParams, setSearchParams] = useState<API.EvaluateScoreSearchParams>({});
const [record, setRecord] = useState<API.EvaluateSupplierRecord | null>(null);
const [evaluateRules, setEvaluateRules] = useState<API.EvaluateRuleItem[]>([]);
// 评价等级选项
const levelOptions = Object.entries(EvaluateLevelText).map(([value, label]) => ({
label,
value,
}));
// 获取评价规则列表
const fetchEvaluateRules = async () => {
try {
const response = await getAllEvaluateRules();
if (response.success && response.data) {
setEvaluateRules(response.data);
} else {
message.error(response.message || '获取评价规则列表失败');
}
} catch (error) {
console.error('获取评价规则列表失败:', error);
message.error('获取评价规则列表失败');
}
};
// 首次加载获取评价规则列表
useEffect(() => {
fetchEvaluateRules();
}, []);
// 获取上级页面传递的数据
useEffect(() => {
console.log(location.state);
if (location.state?.record) {
setSupplierRecord(location.state.record);
setRecord(location.state.record);
}
}, [location]);
// 模拟获取评价打分情况列表
// 获取评价打分情况列表
const fetchScoreList = async (
current = 1,
pageSize = 10,
params: any = searchParams,
params: API.EvaluateScoreSearchParams = searchParams,
) => {
// 确保有必要的参数
if (!record?.supplierId || !record?.evaluateTaskId) {
message.error('缺少必要参数,无法获取数据');
return;
}
// 更新搜索参数状态
if (params !== searchParams) {
setSearchParams(params);
@ -66,88 +112,76 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
setLoading(true);
try {
// 模拟API请求
setTimeout(() => {
// 模拟数据
const mockData = Array.from({ length: 35 }).map((_, index) => {
const id = `${index + 1}`;
// 构建请求参数
const requestParams: API.EvaluateScoreRequest = {
basePageRequest: {
pageNo: current,
pageSize: pageSize,
},
taskId: record.evaluateTaskId,
supplierId: record.supplierId,
...params,
};
// 随机生成得分
const score = Math.floor(Math.random() * 40) + 60; // 60-100分
// 调用接口获取数据
const response = await getEvaluateScoreList(requestParams);
// 评价单位
const units = ['中山市合创展包装材料有限公司', '广州市科技发展有限公司', '深圳市创新科技有限公司', '东莞市制造业有限公司'];
const unitIndex = Math.floor(Math.random() * units.length);
// 新的接口返回格式,结构是: { success, data: { records, total, ... } }
if (response.success && response.data) {
const { records = [], total = 0, size = 10, current: currentPage = 1 } = response.data;
return {
id,
key: id,
supplierName: supplierRecord?.supplierName || `供应商${index + 1}`,
category: supplierRecord?.category || '电子',
evaluateUnit: units[unitIndex],
evaluator: `评价人${index + 1}`,
evaluateTime: `2023-${Math.floor(Math.random() * 12) + 1}-${Math.floor(Math.random() * 28) + 1}`,
score,
};
});
if (records && records.length > 0) {
// 格式化数据用于表格显示 - 使用新的字段名称
const formattedData = records.map((item: any, index: number) => ({
...item,
key: index.toString(),
supplierName: item.name || '-',
evaluateTheme: item.evaluateTheme || '-',
evaluateTime: item.endTime || item.startTime || '-',
score: item.suscore || '0',
status: item.statusName || '-',
categoryName: item.categoryName || '-', // 品类
deptName: item.deptName || '-', // 评价单位
evaluatorName: item.evaluatorName || item.createBy || '-', // 评价人员
}));
// 根据搜索条件过滤
let filteredData = [...mockData];
if (params.supplierName) {
filteredData = filteredData.filter((item) =>
item.supplierName.includes(params.supplierName || ''),
);
}
if (params.level) {
filteredData = filteredData.filter((item) => {
let level;
if (item.score >= 90) {
level = EvaluateLevel.EXCELLENT;
} else if (item.score >= 80) {
level = EvaluateLevel.GOOD;
} else if (item.score >= 70) {
level = EvaluateLevel.AVERAGE;
} else {
level = EvaluateLevel.POOR;
}
return level === params.level;
setScoreData(formattedData);
setPagination({
...pagination,
current: currentPage,
pageSize: size,
total,
});
} else {
setScoreData([]);
setPagination({
...pagination,
current,
pageSize,
total: 0,
});
message.info('暂无评价打分数据');
}
// 分页
const startIndex = (current - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedData = filteredData.slice(startIndex, endIndex);
setScoreData(paginatedData);
setPagination({
...pagination,
current,
pageSize,
total: filteredData.length,
});
setLoading(false);
}, 500);
} else {
message.error(response.message || '获取评价打分情况列表失败');
}
} catch (error) {
console.error('获取评价打分情况列表失败:', error);
message.error('获取评价打分情况列表失败');
} finally {
setLoading(false);
}
};
// 首次加载获取数据
useEffect(() => {
fetchScoreList(pagination.current, pagination.pageSize, {});
}, []);
// 处理表格分页变化
const handleTableChange = (newPagination: TablePaginationConfig) => {
fetchScoreList(newPagination.current, newPagination.pageSize, searchParams);
};
if (record?.supplierId && record?.evaluateTaskId) {
fetchScoreList(pagination.current, pagination.pageSize);
}
}, [record]);
// 处理搜索
const handleSearch = (values: any) => {
const handleSearch = (values: API.EvaluateScoreSearchParams) => {
fetchScoreList(1, pagination.pageSize, values);
};
@ -163,25 +197,34 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
};
// 查看评价详情
const handleViewDetail = (record: any) => {
const handleViewDetail = (scoreItem: ScoreDataItem) => {
const detailState: DetailPageState = {
record: scoreItem,
parentRecord: record
};
history.push({
pathname: 'supplierEvaluateResultByZb',
state: { record }
state: detailState,
});
};
// 处理表格分页变化
const handleTableChange = (newPagination: TablePaginationConfig) => {
fetchScoreList(newPagination.current, newPagination.pageSize, searchParams);
};
const columns = [
{
title: '序号',
render: (_: any, __: any, index: number) =>
(pagination.current! - 1) * pagination.pageSize! + index + 1,
width: 80,
width: 60,
},
{
title: '供应商名称',
dataIndex: 'supplierName',
key: 'supplierName',
width: 200,
width: 180,
ellipsis: {
showTitle: false,
},
@ -193,15 +236,23 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
},
{
title: '品类',
dataIndex: 'category',
key: 'category',
dataIndex: 'categoryName',
key: 'categoryName',
width: 120,
ellipsis: {
showTitle: false,
},
render: (text: string) => (
<Tooltip placement="topLeft" title={text}>
{text}
</Tooltip>
),
},
{
title: '评价单位',
dataIndex: 'evaluateUnit',
key: 'evaluateUnit',
width: 180,
dataIndex: 'deptName',
key: 'deptName',
width: 150,
ellipsis: {
showTitle: false,
},
@ -213,9 +264,17 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
},
{
title: '评价人员',
dataIndex: 'evaluator',
key: 'evaluator',
dataIndex: 'evaluatorName',
key: 'evaluatorName',
width: 120,
ellipsis: {
showTitle: false,
},
render: (text: string) => (
<Tooltip placement="topLeft" title={text}>
{text}
</Tooltip>
),
},
{
title: '评价时间',
@ -233,13 +292,10 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
{
title: '操作',
key: 'action',
width: 100,
width: 80,
align: 'center' as const,
render: (_: unknown, record: any) => (
<Button
type="link"
onClick={() => handleViewDetail(record)}
>
render: (_: unknown, scoreItem: ScoreDataItem) => (
<Button type="link" onClick={() => handleViewDetail(scoreItem)}>
</Button>
),
@ -255,9 +311,9 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
</Form.Item>
<Form.Item name="level" label="评价等级">
<Select placeholder="请选择评价等级" allowClear style={{ width: 150 }}>
{levelOptions.map((option) => (
<Option key={option.value} value={option.value}>
{option.label}
{evaluateRules.map((rule) => (
<Option key={rule.id} value={rule.levelName}>
{rule.levelName}
</Option>
))}
</Select>
@ -285,7 +341,7 @@ const SupplierEvaluateResultScoreByList: React.FC = () => {
pagination={pagination}
loading={loading}
onChange={handleTableChange}
scroll={{ x: 1100 }}
scroll={{ x: 1200 }}
/>
</div>
</div>

View File

@ -1,37 +1,93 @@
// 供应商评价结果得分明细
import React, { useState, useEffect } from 'react';
import { Tabs, Button, Typography, Row, Col } from 'antd';
import { Button, Typography, Card, Spin, message } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { history, useLocation } from 'umi';
import GeneralEvaluation from './components/GeneralEvaluation';
import TechnicalEvaluation from './components/TechnicalEvaluation';
import ScoreEvaluationTable from '@/components/ScoreEvaluationTable';
import styles from './supplierEvaluateResult.less';
import { getSupplierScoreDetail } from '@/servers/api/supplierEvaluate';
const { Title } = Typography;
const { TabPane } = Tabs;
const SupplierEvaluateResultScoreDetail: React.FC = () => {
const location = useLocation<{ record: SupplierEvaluate.EvaluateResultDetailRecord }>();
const [supplierRecord, setSupplierRecord] = useState<SupplierEvaluate.EvaluateResultDetailRecord | null>(null);
const [activeTab, setActiveTab] = useState<string>('1');
const location = useLocation<{
record: API.EvaluateSupplierRecord;
parentRecord: API.EvaluateTaskRecord;
}>();
const [loading, setLoading] = useState<boolean>(false);
const [supplierRecord, setSupplierRecord] = useState<API.EvaluateSupplierRecord | null>(null);
const [parentRecord, setParentRecord] = useState<API.EvaluateTaskRecord | null>(null);
const [scoreDetail, setScoreDetail] = useState<API.EvaluateScoreDetailData | null>(null);
// 获取上级页面传递的数据
useEffect(() => {
if (location.state?.record) {
setSupplierRecord(location.state.record);
}
if (location.state?.parentRecord) {
setParentRecord(location.state.parentRecord);
}
}, [location]);
// 处理Tab切换
const handleTabChange = (key: string) => {
setActiveTab(key);
// 获取得分明细数据
const fetchScoreDetail = async () => {
if (!supplierRecord?.id) {
message.error('缺少必要参数,无法获取数据');
return;
}
setLoading(true);
try {
const response = await getSupplierScoreDetail(supplierRecord.id);
if (response.success && response.data) {
setScoreDetail(response.data);
} else {
message.error(response.message || '获取评价得分明细失败');
}
} catch (error) {
console.error('获取评价得分明细失败:', error);
message.error('获取评价得分明细失败');
} finally {
setLoading(false);
}
};
// 当供应商记录加载完成后,获取得分明细
useEffect(() => {
if (supplierRecord?.id) {
fetchScoreDetail();
}
}, [supplierRecord]);
// 返回上一页
const handleBack = () => {
history.goBack();
};
// 将API数据转换为ScoreEvaluationTable组件所需的格式
const formatDataForScoreTable = () => {
if (!scoreDetail?.taskIndicatorVo) return [];
return scoreDetail.taskIndicatorVo.map(indicator => {
return {
baseIndicator: indicator.baseIndicator,
descIndicator: indicator.indicatorDesc,
score: indicator.score,
indicatorNdList: indicator.subIndicator?.map(subItem => {
return {
subIndicator: subItem.subIndicator,
score: subItem.subScore,
isStar: subItem.starIndicator,
id: subItem.id,
actualScore: subItem.scoreNum || subItem.subScore,
remark: subItem.remark || ''
};
}) || []
};
});
};
return (
<div className="common-container">
<div className={styles.headerRow}>
@ -48,14 +104,19 @@ const SupplierEvaluateResultScoreDetail: React.FC = () => {
</div>
<div className="content-area">
<Tabs activeKey={activeTab} onChange={handleTabChange} type="card">
<TabPane tab="通用评价" key="1">
<GeneralEvaluation supplierName={supplierRecord?.supplierName} />
</TabPane>
<TabPane tab="技术评价" key="2">
<TechnicalEvaluation supplierName={supplierRecord?.supplierName} />
</TabPane>
</Tabs>
<Card bordered={false}>
{loading ? (
<div className="loading-container" style={{ textAlign: 'center', padding: '50px' }}>
<Spin tip="加载中..." />
</div>
) : (
<ScoreEvaluationTable
value={formatDataForScoreTable()}
isDetail={true}
loading={loading}
/>
)}
</Card>
</div>
</div>
);

View File

@ -0,0 +1,347 @@
import React, { useState, useEffect } from 'react';
import { Button, Table, Space, message, Tooltip, Modal, Tag, Form, Input, InputNumber } from 'antd';
import { PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import type { TablePaginationConfig } from 'antd';
import { useIntl, FormattedMessage } from 'umi';
import {
getAllEvaluateRules,
getEvaluateRuleDetail,
addEvaluateRule,
updateEvaluateRule,
deleteEvaluateRule
} from '@/servers/api/supplierEvaluate';
// 定义规则表单数据类型
interface RuleFormData {
id?: string;
beginValue: string;
endValue: string;
levelName: string;
ratingName?: string;
remark?: string;
}
const SupplierEvaluateRuleManage: React.FC = () => {
const intl = useIntl();
const [loading, setLoading] = useState<boolean>(false);
const [ruleData, setRuleData] = useState<API.EvaluateRuleItem[]>([]);
const [form] = Form.useForm();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [modalTitle, setModalTitle] = useState<string>(intl.formatMessage({ id: 'supplierEvaluateRuleManage.modal.add' }));
const [editingRule, setEditingRule] = useState<API.EvaluateRuleItem | null>(null);
const [confirmLoading, setConfirmLoading] = useState<boolean>(false);
// 获取规则列表
const fetchRuleList = async () => {
setLoading(true);
try {
const response = await getAllEvaluateRules();
if (response.success && response.data) {
setRuleData(response.data);
} else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.getList.error' }));
}
} catch (error) {
console.error('获取评价规则列表失败:', error);
message.error(intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.getList.error' }));
} finally {
setLoading(false);
}
};
// 首次加载获取数据
useEffect(() => {
fetchRuleList();
}, []);
// 处理添加规则
const handleAdd = () => {
setModalTitle(intl.formatMessage({ id: 'supplierEvaluateRuleManage.modal.add' }));
setEditingRule(null);
form.resetFields();
setModalVisible(true);
};
// 处理编辑规则
const handleEdit = async (record: API.EvaluateRuleItem) => {
setModalTitle(intl.formatMessage({ id: 'supplierEvaluateRuleManage.modal.edit' }));
setEditingRule(record);
try {
// 获取规则详情
const response = await getEvaluateRuleDetail(record.id);
if (response.success && response.data) {
const ruleDetail = response.data;
form.setFieldsValue({
id: ruleDetail.id,
beginValue: ruleDetail.beginValue,
endValue: ruleDetail.endValue,
levelName: ruleDetail.levelName,
ratingName: ruleDetail.ratingName || '',
remark: ruleDetail.remark || '',
});
setModalVisible(true);
} else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.getDetail.error' }));
}
} catch (error) {
console.error('获取评价规则详情失败:', error);
message.error(intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.getDetail.error' }));
}
};
// 处理删除规则
const handleDelete = (record: API.EvaluateRuleItem) => {
Modal.confirm({
title: intl.formatMessage({ id: 'supplierEvaluateRuleManage.modal.delete' }),
icon: <ExclamationCircleOutlined />,
content: intl.formatMessage(
{ id: 'supplierEvaluateRuleManage.modal.delete.content' },
{ levelName: record.levelName }
),
okText: intl.formatMessage({ id: 'supplierEvaluateRuleManage.confirm' }),
cancelText: intl.formatMessage({ id: 'supplierEvaluateRuleManage.cancel' }),
onOk: async () => {
try {
const response = await deleteEvaluateRule(record.id);
if (response.success) {
message.success(
intl.formatMessage(
{ id: 'supplierEvaluateRuleManage.message.delete.success' },
{ levelName: record.levelName }
)
);
fetchRuleList(); // 刷新列表
} else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.delete.error' }));
}
} catch (error) {
console.error('删除评价规则失败:', error);
message.error(intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.delete.error' }));
}
},
});
};
// 处理表单提交
const handleFormSubmit = async () => {
try {
const values = await form.validateFields();
setConfirmLoading(true);
if (editingRule) {
// 更新规则
const updateParams: API.EvaluateRuleUpdateRequest = {
id: editingRule.id,
beginValue: String(values.beginValue),
endValue: String(values.endValue),
levelName: values.levelName,
remark: values.remark,
};
const response = await updateEvaluateRule(updateParams);
if (response.success) {
message.success(intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.update.success' }));
setModalVisible(false);
fetchRuleList(); // 刷新列表
} else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.update.error' }));
}
} else {
// 新增规则
const addParams: API.EvaluateRuleAddRequest = {
beginValue: String(values.beginValue),
endValue: String(values.endValue),
levelName: values.levelName,
ratingName: values.ratingName || '',
remark: values.remark,
};
const response = await addEvaluateRule(addParams);
if (response.success) {
message.success(intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.add.success' }));
setModalVisible(false);
fetchRuleList(); // 刷新列表
} else {
message.error(response.message || intl.formatMessage({ id: 'supplierEvaluateRuleManage.message.add.error' }));
}
}
} catch (error) {
console.error('表单验证或提交失败:', error);
} finally {
setConfirmLoading(false);
}
};
// 取消表单
const handleCancel = () => {
setModalVisible(false);
};
const columns = [
{
title: <FormattedMessage id="supplierEvaluateRuleManage.column.index" />,
render: (_: any, __: any, index: number) => index + 1,
width: 80,
},
{
title: <FormattedMessage id="supplierEvaluateRuleManage.column.levelName" />,
dataIndex: 'levelName',
key: 'levelName',
width: 120,
},
{
title: <FormattedMessage id="supplierEvaluateRuleManage.column.ratingName" />,
dataIndex: 'ratingName',
key: 'ratingName',
width: 150,
render: (ratingName: string) => ratingName || '-',
},
{
title: <FormattedMessage id="supplierEvaluateRuleManage.column.scoreRange" />,
key: 'scoreRange',
width: 150,
render: (_: any, record: API.EvaluateRuleItem) => `${record.beginValue} - ${record.endValue}`,
},
{
title: <FormattedMessage id="supplierEvaluateRuleManage.column.remark" />,
dataIndex: 'remark',
key: 'remark',
width: 200,
ellipsis: {
showTitle: false,
},
render: (remark: string) => (
<Tooltip placement="topLeft" title={remark}>
{remark || '-'}
</Tooltip>
),
},
{
title: <FormattedMessage id="supplierEvaluateRuleManage.column.action" />,
key: 'action',
width: 150,
align: 'center' as const,
render: (_: unknown, record: API.EvaluateRuleItem) => (
<Space size="middle">
<Button type="link" onClick={() => handleEdit(record)}>
<FormattedMessage id="supplierEvaluateRuleManage.edit" />
</Button>
<Button type="link" onClick={() => handleDelete(record)}>
<FormattedMessage id="supplierEvaluateRuleManage.delete" />
</Button>
</Space>
),
},
];
return (
<div className="common-container">
<div className="action-row" style={{ marginBottom: '16px', display: 'flex', justifyContent: 'flex-end' }}>
<Button type="primary" ghost icon={<PlusOutlined />} onClick={handleAdd}>
<FormattedMessage id="supplierEvaluateRuleManage.add" />
</Button>
</div>
<div className="content-area">
<Table
columns={columns}
dataSource={ruleData}
loading={loading}
rowKey="id"
scroll={{ x: 1500 }}
/>
</div>
{/* 新增/编辑规则模态框 */}
<Modal
title={modalTitle}
visible={modalVisible}
onCancel={handleCancel}
maskClosable={false}
width={600}
confirmLoading={confirmLoading}
onOk={handleFormSubmit}
okText={intl.formatMessage({ id: 'supplierEvaluateRuleManage.submit' })}
cancelText={intl.formatMessage({ id: 'supplierEvaluateRuleManage.cancel' })}
>
<Form
form={form}
layout="vertical"
initialValues={{
beginValue: '',
endValue: '',
levelName: '',
ratingName: '',
remark: '',
}}
>
{editingRule && (
<Form.Item name="id" hidden>
<Input />
</Form.Item>
)}
<Form.Item
name="levelName"
label={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.levelName' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.levelName.required' }) }]}
>
<Input placeholder={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.levelName.placeholder' })} />
</Form.Item>
<Form.Item
name="ratingName"
label={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.ratingName' })}
rules={[{ required: !editingRule, message: intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.ratingName.required' }) }]}
>
<Input placeholder={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.ratingName.placeholder' })} />
</Form.Item>
<Form.Item
name="beginValue"
label={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.beginValue' })}
rules={[
{ required: true, message: intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.beginValue.required' }) },
{
pattern: /^[1-9]\d*$/,
message: intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.beginValue.integer' })
}
]}
>
<InputNumber min={0} precision={0} style={{ width: '100%' }} placeholder={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.beginValue.placeholder' })} />
</Form.Item>
<Form.Item
name="endValue"
label={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.endValue' })}
rules={[
{ required: true, message: intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.endValue.required' }) },
{
pattern: /^[1-9]\d*$/,
message: intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.endValue.integer' })
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || !getFieldValue('beginValue')) {
return Promise.resolve();
}
if (parseInt(value) <= parseInt(getFieldValue('beginValue'))) {
return Promise.reject(new Error(intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.endValue.greater' })));
}
return Promise.resolve();
},
}),
]}
>
<InputNumber min={0} precision={0} style={{ width: '100%' }} placeholder={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.endValue.placeholder' })} />
</Form.Item>
<Form.Item
name="remark"
label={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.remark' })}
>
<Input.TextArea rows={4} placeholder={intl.formatMessage({ id: 'supplierEvaluateRuleManage.form.remark.placeholder' })} />
</Form.Item>
</Form>
</Modal>
</div>
);
};
export default SupplierEvaluateRuleManage;

View File

@ -0,0 +1,21 @@
// 供应商评价打分页面样式
.headerRow {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.titleSection {
flex: 1;
.pageTitle {
margin-bottom: 0;
}
}
.actionSection {
display: flex;
justify-content: flex-end;
align-items: center;
}
}

View File

@ -1,346 +1,203 @@
// 供应商评价打分
import React, { useState, useEffect } from 'react';
import {
Card,
Form,
Input,
Select,
Button,
Table,
Space,
Tag,
DatePicker,
TablePaginationConfig,
Tooltip,
message,
} from 'antd';
import {
SearchOutlined,
DeleteOutlined,
PlusOutlined,
EditOutlined,
EyeOutlined,
FormOutlined,
} from '@ant-design/icons';
import { TaskStatus, TaskStatusText, TaskStatusColor } from '@/dicts/supplierTaskDict';
import moment from 'moment';
import { Button, Card, Form, message, Typography, Spin, Space } from 'antd';
import { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';
import { history, useLocation } from 'umi';
import ScoreEvaluationTable from '@/components/ScoreEvaluationTable';
import styles from './supplierEvaluateScore.less';
import { getSupplierScoreDetail, submitEvaluateScore } from '@/servers/api/supplierEvaluate';
const { Option } = Select;
const { RangePicker } = DatePicker;
// 定义搜索参数接口
interface ScoreSearchParams {
evaluateTitle?: string;
supplierName?: string;
status?: string;
}
// 定义打分记录接口
interface ScoreRecord {
id: string;
evaluateTitle: string;
supplierName: string;
category: string;
status: string;
scoreStatus: string; // 打分状态:未打分、已打分、已提交
createTime: string;
key: string;
}
// 打分状态
const ScoreStatus = {
NOT_SCORED: 'not_scored',
SCORED: 'scored',
SUBMITTED: 'submitted',
};
const ScoreStatusText = {
[ScoreStatus.NOT_SCORED]: '未打分',
[ScoreStatus.SCORED]: '已打分',
[ScoreStatus.SUBMITTED]: '已提交',
};
const ScoreStatusColor = {
[ScoreStatus.NOT_SCORED]: 'orange',
[ScoreStatus.SCORED]: 'blue',
[ScoreStatus.SUBMITTED]: 'green',
};
const { Title } = Typography;
const SupplierEvaluateScore: React.FC = () => {
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
const [scoreData, setScoreData] = useState<ScoreRecord[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total} 条记录`,
});
const [searchParams, setSearchParams] = useState<ScoreSearchParams>({});
const location = useLocation<{
record: API.EvaluateSupplierRecord;
parentRecord: API.EvaluateTaskRecord;
}>();
const [loading, setLoading] = useState<boolean>(false);
const [submitting, setSubmitting] = useState<boolean>(false);
const [supplierRecord, setSupplierRecord] = useState<API.EvaluateSupplierRecord | null>(null);
const [parentRecord, setParentRecord] = useState<API.EvaluateTaskRecord | null>(null);
const [scoreDetail, setScoreDetail] = useState<API.EvaluateScoreDetailData | null>(null);
const [scoreData, setScoreData] = useState<any[]>([]);
// 品类数据
const categoryOptions = [
{ label: '食品', value: '食品' },
{ label: '电子', value: '电子' },
{ label: '机械', value: '机械' },
{ label: '化工', value: '化工' },
{ label: '医药', value: '医药' },
];
// 获取上级页面传递的数据
useEffect(() => {
if (location.state?.record) {
setSupplierRecord(location.state.record);
}
if (location.state?.parentRecord) {
setParentRecord(location.state.parentRecord);
}
}, [location]);
// 模拟获取打分列表
const fetchScoreList = async (
current = 1,
pageSize = 10,
params: ScoreSearchParams = searchParams,
) => {
// 更新搜索参数状态
if (params !== searchParams) {
setSearchParams(params);
// 将API数据转换为ScoreEvaluationTable组件所需的格式
const formatDataForScoreTable = (data: API.EvaluateScoreDetailData | null) => {
if (!data?.taskIndicatorVo) return [];
return data.taskIndicatorVo.map(indicator => {
return {
baseIndicator: indicator.baseIndicator,
descIndicator: indicator.indicatorDesc,
score: indicator.score,
indicatorNdList: indicator.subIndicator?.map(subItem => {
return {
subIndicator: subItem.subIndicator,
score: subItem.subScore,
isStar: subItem.starIndicator,
id: subItem.id,
actualScore: subItem.scoreNum || '',
remark: subItem.remark || ''
};
}) || []
};
});
};
// 获取得分明细数据
const fetchScoreDetail = async () => {
if (!supplierRecord?.id) {
message.error('缺少必要参数,无法获取数据');
return;
}
setLoading(true);
try {
// 模拟API请求
setTimeout(() => {
// 模拟数据
const mockData: ScoreRecord[] = Array.from({ length: 35 }).map((_, index) => {
const id = `${index + 1}`;
const status = Object.values(TaskStatus)[Math.floor(Math.random() * 3)];
const scoreStatus = Object.values(ScoreStatus)[Math.floor(Math.random() * 3)];
const response = await getSupplierScoreDetail(supplierRecord.id);
// 随机选择品类
const categoryIndex = Math.floor(Math.random() * categoryOptions.length);
if (response.success && response.data) {
setScoreDetail(response.data);
return {
id,
key: id,
evaluateTitle: `供应商评价任务${index + 1}`,
supplierName: `供应商${index + 1}`,
category: categoryOptions[categoryIndex].value,
status,
scoreStatus,
createTime: moment().subtract(Math.floor(Math.random() * 90), 'days').format('YYYY-MM-DD HH:mm:ss'),
};
});
// 根据搜索条件过滤
let filteredData = [...mockData];
if (params.evaluateTitle) {
filteredData = filteredData.filter(item =>
item.evaluateTitle.includes(params.evaluateTitle || '')
);
}
if (params.supplierName) {
filteredData = filteredData.filter(item =>
item.supplierName.includes(params.supplierName || '')
);
}
if (params.status) {
filteredData = filteredData.filter(item =>
item.scoreStatus === params.status
);
}
// 分页
const startIndex = (current - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedData = filteredData.slice(startIndex, endIndex);
setScoreData(paginatedData);
setPagination({
...pagination,
current,
pageSize,
total: filteredData.length,
});
setLoading(false);
}, 500);
// 转换数据格式
const formattedData = formatDataForScoreTable(response.data);
setScoreData(formattedData);
} else {
message.error(response.message || '获取评价得分明细失败');
}
} catch (error) {
console.error('获取打分列表失败:', error);
message.error('获取打分列表失败');
console.error('获取评价得分明细失败:', error);
message.error('获取评价得分明细失败');
} finally {
setLoading(false);
}
};
// 首次加载获取数据
// 当供应商记录加载完成后,获取得分明细
useEffect(() => {
fetchScoreList(pagination.current, pagination.pageSize, {});
}, []);
if (supplierRecord?.id) {
fetchScoreDetail();
}
}, [supplierRecord]);
// 处理表格分页变化
const handleTableChange = (newPagination: TablePaginationConfig) => {
fetchScoreList(newPagination.current, newPagination.pageSize, searchParams);
// 返回上一页
const handleBack = () => {
history.goBack();
};
// 处理搜索
const handleSearch = (values: any) => {
fetchScoreList(1, pagination.pageSize, values);
// 处理评分数据变更
const handleScoreDataChange = (newData: any[]) => {
setScoreData(newData);
};
// 处理重置
const handleReset = () => {
form.resetFields();
fetchScoreList(1, pagination.pageSize, {});
};
// 提交评分
const handleSubmit = async () => {
if (!supplierRecord?.id) {
message.error('缺少必要参数,无法提交');
return;
}
// 处理打
const handleScore = (record: ScoreRecord) => {
message.info(`开始为 ${record.supplierName} 打分`);
};
// 验证所有二级指标是否都已评
const hasEmptyScore = scoreData.some(item =>
item.indicatorNdList.some((subItem: any) =>
!subItem.actualScore && subItem.actualScore !== 0
)
);
// 处理查看
const handleView = (record: ScoreRecord) => {
message.info(`查看 ${record.supplierName} 的打分情况`);
};
if (hasEmptyScore) {
message.warning('请为所有指标填写评分');
return;
}
// 处理提交
const handleSubmit = (record: ScoreRecord) => {
message.success(`已提交 ${record.supplierName} 的评分`);
fetchScoreList(pagination.current, pagination.pageSize, searchParams);
};
setSubmitting(true);
try {
// 构建提交数据
const submitData = {
id: supplierRecord.id,
taskIndicatorVo: scoreData.map(item => ({
baseIndicator: item.baseIndicator,
indicatorDesc: item.descIndicator,
score: item.score,
subIndicator: item.indicatorNdList.map((subItem: any) => ({
id: subItem.id,
subIndicator: subItem.subIndicator,
subScore: subItem.score,
starIndicator: subItem.isStar,
scoreNum: subItem.actualScore,
remark: subItem.remark
}))
}))
};
// 获取状态标签
const getScoreStatusTag = (status: string) => {
const color = ScoreStatusColor[status as keyof typeof ScoreStatusColor] || 'default';
const text = ScoreStatusText[status as keyof typeof ScoreStatusText] || '未知状态';
return <Tag color={color}>{text}</Tag>;
};
const response = await submitEvaluateScore(submitData);
const columns = [
{
title: '序号',
render: (_: any, __: ScoreRecord, index: number) =>
(pagination.current! - 1) * pagination.pageSize! + index + 1,
width: 80,
},
{
title: '评价主题',
dataIndex: 'evaluateTitle',
key: 'evaluateTitle',
width: 200,
ellipsis: {
showTitle: false,
},
render: (evaluateTitle: string) => (
<Tooltip placement="topLeft" title={evaluateTitle}>
{evaluateTitle}
</Tooltip>
),
},
{
title: '供应商名称',
dataIndex: 'supplierName',
key: 'supplierName',
width: 150,
ellipsis: {
showTitle: false,
},
render: (supplierName: string) => (
<Tooltip placement="topLeft" title={supplierName}>
{supplierName}
</Tooltip>
),
},
{
title: '品类',
dataIndex: 'category',
key: 'category',
width: 120,
},
{
title: '打分状态',
dataIndex: 'scoreStatus',
key: 'scoreStatus',
width: 100,
render: (status: string) => getScoreStatusTag(status),
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
width: 150,
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center' as const,
render: (_: unknown, record: ScoreRecord) => (
<Space size="middle">
{record.scoreStatus === ScoreStatus.NOT_SCORED && (
<Button
type="link"
icon={<FormOutlined />}
onClick={() => handleScore(record)}
>
</Button>
)}
{record.scoreStatus === ScoreStatus.SCORED && (
<Button
type="link"
icon={<EditOutlined />}
onClick={() => handleSubmit(record)}
>
</Button>
)}
<Button
type="link"
icon={<EyeOutlined />}
onClick={() => handleView(record)}
>
</Button>
</Space>
),
},
];
if (response.success) {
message.success('评分提交成功');
// 提交成功后返回列表页
history.goBack();
} else {
message.error(response.message || '评分提交失败');
}
} catch (error) {
console.error('评分提交失败:', error);
message.error('评分提交失败');
} finally {
setSubmitting(false);
}
};
return (
<div className="common-container">
<div className="filter-action-row">
<Form form={form} layout="inline" onFinish={handleSearch} className="filter-form">
<Form.Item name="evaluateTitle" label="评价主题">
<Input placeholder="请输入评价主题" allowClear />
</Form.Item>
<Form.Item name="supplierName" label="供应商名称">
<Input placeholder="请输入供应商名称" allowClear />
</Form.Item>
<Form.Item name="status" label="打分状态">
<Select placeholder="请选择状态" allowClear style={{ width: 150 }}>
<Option value={ScoreStatus.NOT_SCORED}>{ScoreStatusText[ScoreStatus.NOT_SCORED]}</Option>
<Option value={ScoreStatus.SCORED}>{ScoreStatusText[ScoreStatus.SCORED]}</Option>
<Option value={ScoreStatus.SUBMITTED}>{ScoreStatusText[ScoreStatus.SUBMITTED]}</Option>
</Select>
</Form.Item>
<Form.Item className="filter-btns">
<Button type="primary" icon={<SearchOutlined />} onClick={() => form.submit()}>
<div className={styles.headerRow}>
<div className={styles.titleSection}>
<Title level={4} className={styles.pageTitle}>
{supplierRecord?.supplierName || '供应商'} -
</Title>
</div>
<div className={styles.actionSection}>
<Space>
<Button type="link" icon={<ArrowLeftOutlined />} onClick={handleBack}>
</Button>
<Button type="primary" danger icon={<DeleteOutlined />} onClick={handleReset}>
<Button
type="primary"
icon={<SaveOutlined />}
onClick={handleSubmit}
loading={submitting}
>
</Button>
</Form.Item>
</Form>
<div className="right-buttons">
<Button type="primary" ghost icon={<PlusOutlined />} onClick={() => message.info('新增打分任务')}>
</Button>
</Space>
</div>
</div>
<div className="content-area">
<Table
columns={columns}
dataSource={scoreData}
pagination={pagination}
loading={loading}
onChange={handleTableChange}
scroll={{ x: 1100 }}
/>
<Card bordered={false}>
{loading ? (
<div className="loading-container" style={{ textAlign: 'center', padding: '50px' }}>
<Spin tip="加载中..." />
</div>
) : (
<Form form={form} layout="vertical">
<ScoreEvaluationTable
value={scoreData}
onChange={handleScoreDataChange}
isDetail={false}
loading={loading}
/>
</Form>
)}
</Card>
</div>
</div>
);

View File

@ -32,7 +32,23 @@
}
}
.template-indicator-card {
margin-bottom: 24px;
.indicator-area {
padding: 16px 0;
}
.ant-card-head {
padding: 0 0 16px 0;
border-bottom: 1px solid #f0f0f0;
}
.ant-card-head-title {
font-size: 16px;
font-weight: 500;
}
}
.form-actions {
margin-top: 24px;

View File

@ -322,6 +322,7 @@ const SupplierTemplateManage: React.FC = () => {
<div className="content-area">
<Table
columns={columns}
rowKey="id"
dataSource={templateData}
pagination={pagination}
loading={loading}

View File

@ -13,7 +13,7 @@ import {
CategoryLimitationTypeText,
StarLevel,
} from '@/dicts/supplierTemplateDict';
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable';
import ScoreEvaluationTable from '@/components/ScoreEvaluationTable';
const { Title } = Typography;
@ -114,7 +114,7 @@ const SupplierTemplateManageDetail: React.FC = () => {
<Card title="评价指标" bordered={false}>
{templateData.length > 0 ? (
<EvaluateTemplateTable
<ScoreEvaluationTable
value={templateData}
isDetail={true}
/>

View File

@ -206,3 +206,130 @@ export async function getEvaluateResultList(params: API.EvaluateTaskRequest) {
data: params,
});
}
/**
* 获取评价结果详情列表(供应商列表)
* @param params 查询参数
* @returns Promise
*/
export async function getEvaluateSupplierList(params: API.EvaluateSupplierRequest) {
return request<API.APIResponse<API.EvaluateSupplierData>>('/coscoEvaluate/supplier/getPage', {
method: 'POST',
data: params,
});
}
/**
* 获取供应商评价打分情况
* @param params 查询参数
* @returns Promise
*/
export async function getEvaluateScoreList(params: API.EvaluateScoreRequest) {
return request<API.APIResponse<API.PageResponse<any>>>('/coscoEvaluate/supplier/getSupplierDimension', {
method: 'POST',
data: params,
});
}
/**
* 获取评价打分详情
* @param id 评价记录ID
* @returns Promise
*/
export async function getEvaluateScoreDetail(id: string) {
return request<API.APIResponse<API.EvaluateScoreDetailData>>(`/coscoEvaluate/user/getIndicator?id=${id}`, {
method: 'GET',
});
}
/**
* 获取所有评价规则列表
* @returns Promise
*/
export async function getAllEvaluateRules() {
return request<API.EvaluateRuleResponse>('/coscoEvaluate/level/getAllList', {
method: 'GET',
});
}
/**
* 获取评价规则详情
* @param id 规则ID
* @returns Promise
*/
export async function getEvaluateRuleDetail(id: string) {
return request<API.EvaluateRuleDetailResponse>(`/coscoEvaluate/level/${id}`, {
method: 'GET',
});
}
/**
* 新增评价规则
* @param params 规则数据
* @returns Promise
*/
export async function addEvaluateRule(params: API.EvaluateRuleAddRequest) {
return request<API.APIResponse<any>>('/coscoEvaluate/level', {
method: 'POST',
data: params,
});
}
/**
* 更新评价规则
* @param params 规则数据
* @returns Promise
*/
export async function updateEvaluateRule(params: API.EvaluateRuleUpdateRequest) {
return request<API.APIResponse<any>>('/coscoEvaluate/level', {
method: 'PUT',
data: params,
});
}
/**
* 删除评价规则
* @param id 规则ID
* @returns Promise
*/
export async function deleteEvaluateRule(id: string) {
return request<API.APIResponse<any>>(`/coscoEvaluate/level/${id}`, {
method: 'DELETE',
});
}
/**
* 获取供应商评价得分明细
* @param id 评价记录ID
* @returns Promise
*/
export async function getSupplierScoreDetail(id: string) {
return request<API.APIResponse<API.EvaluateScoreDetailData>>(`/coscoEvaluate/supplier/getScoreResult`, {
method: 'GET',
params: { id }
});
}
/**
* 提交供应商评价得分
* @param params 评价得分数据
* @returns
*/
export async function submitEvaluateScore(params: any) {
return request('/api/supplier/evaluate/score/submit', {
method: 'POST',
data: params,
});
}
/**
* 获取评价打分详情
* @param id 评价记录ID
* @returns
*/
export async function getIndicator(id: string) {
return request('/coscoEvaluate/user/getIndicator', {
method: 'GET',
params: { id },
});
}

View File

@ -6,33 +6,6 @@ declare namespace API {
data: T;
}
export type PolicyRequest = {
/**
* 内容
*/
content: string;
/**
* 内容_英文版
*/
contentEn: string;
/**
* 是否置顶(0.否、1.是)
*/
isTop: string;
/**
* 是否设置英文内容(0.否、1.是)
*/
settingEn: number;
/**
* 标题
*/
title: string;
/**
* 标题英文
*/
titleEn: string;
[property: string]: any;
}
export type RegisterRequest = {
coscoSupplierBank: CoscoSupplierBank[];
@ -171,73 +144,6 @@ declare namespace API {
[property: string]: any;
}
// 政策法规数据项
export interface PolicyRecord {
basePageRequest: null;
content: string;
contentEn: string;
createBy: string;
createDate: null;
createTime: string;
deleteFlag: null;
delFlag: string;
id: string;
isTop: string;
lastUpdateTime: null;
publishBy: string | null;
publishTime: string | null;
settingEn: string;
status: string;
tenantId: string | null;
tenantName: string | null;
title: string;
titleEn: string | null;
updateBy: string | null;
updateDate: string | null;
updateTime: string;
}
// 政策法规请求参数
export interface PolicyRequest {
id?: string;
title: string;
titleEn: string;
content: string;
contentEn: string;
isTop: string;
settingEn: number;
}
// 下载中心数据项
export interface DownloadRecord {
id: string;
name: string;
category: string;
keyword: string;
createTime: string;
createBy: string;
status: string; // 状态0-草稿1-已发布
thumbnail?: string; // 缩略图URL
fileUrl?: string; // 文件URL
}
// 下载中心请求参数
export interface DownloadRequest {
id?: string;
name: string;
category: string;
keyword: string;
fileId?: string;
thumbnailId?: string;
}
// 下载中心查询参数
export interface DownloadSearchParams {
name?: string;
category?: string;
status?: string;
}
// 文件上传响应
export interface UploadResponse {
id: string;
@ -247,266 +153,7 @@ declare namespace API {
fileUrl: string;
}
// 通知中心数据项
export interface NoticeRecord {
id: string;
title: string;
titleEn?: string;
content: string;
contentEn?: string;
createTime: string;
createBy: string;
status: string; // 状态0-草稿1-已发布2-已下架
isTop: string; // 是否置顶0-否1-是
settingEn?: number; // 是否设置英文0-否1-是
}
// 通知中心请求参数
export interface NoticeRequest {
id?: string;
title: string;
titleEn?: string;
content: string;
contentEn?: string;
isTop: string;
settingEn?: number;
}
// 通知中心查询参数
export interface NoticeSearchParams {
title?: string;
status?: string;
pageNo?: number;
pageSize?: number;
}
// 帮助中心数据项
export interface HelpRecord {
id: string;
title: string;
titleEn?: string;
type: string; // 类型对应页面中的category
content: string;
contentEn?: string;
createTime: string;
createBy: string;
updateTime?: string;
updateBy?: string;
status: string; // 状态0-草稿1-已发布2-已下架
isTop: string; // 是否置顶0-否1-是
settingEn: number; // 是否设置英文0-否1-是
answerContent?: string;
answerContentNe?: string;
publishBy?: string | null;
publishTime?: string | null;
deleteFlag?: null;
delFlag?: string;
tenantId?: string | null;
tenantName?: string | null;
lastUpdateTime?: null;
createDate?: null;
updateDate?: null;
basePageRequest?: null;
}
// 帮助中心请求参数
export interface HelpRequest {
id?: string;
title: string;
titleEn?: string;
type: string; // 类型对应页面中的category
content: string;
contentEn?: string;
isTop: string;
settingEn: number;
answerContent?: string;
answerContentNe?: number;
}
// 帮助中心查询参数
export interface HelpSearchParams {
title?: string;
type?: string; // 类型对应页面中的category
status?: string;
pageNo?: number;
pageSize?: number;
}
// 用户提问数据项
export interface UserQuestionRecord {
id: string;
userId: string;
username: string;
email?: string;
question: string;
answer?: string;
createTime: string;
answerTime?: string;
status: string; // 状态0-未回答1-已回答
}
// 用户提问查询参数
export interface UserQuestionSearchParams {
question?: string;
status?: string;
pageNo?: number;
pageSize?: number;
}
// 用户问题记录类型
interface QuestionRecord {
id: string;
title: string;
type: string;
content: string;
answerContent?: string;
userName: string;
companyName: string;
fullName: string;
contactDetails: string;
email: string;
askTime: string;
answerTime?: string;
answerBy?: string;
isAnswer: string; // 0-未回答1-已回答
isPublished?: number; // 0-未发布1-已发布
isTop?: number; // 0-未置顶1-已置顶
createTime?: string;
updateTime?: string;
}
// 问题列表请求参数
interface QuestionListRequest {
isAnswer?: number; // 0-未回答1-已回答
title?: string;
type?: string;
[property: string]: any;
}
// 问题添加请求参数
interface QuestionAddRequest {
title: string;
content: string;
type: string;
fullName: string;
companyName: string;
userName: string;
contactDetails: string;
email: string;
}
// 问题回答请求参数
interface QuestionAnswerRequest {
id: string;
answerContent: string;
isPublished?: number; // 0-未发布1-已发布
isTop?: number; // 0-未置顶1-已置顶
}
// 问题状态更新请求参数
interface QuestionStatusRequest {
id: string;
isPublished?: number; // 0-未发布1-已发布
isTop?: number; // 0-未置顶1-已置顶
}
// 友情链接分类类型定义
interface CategoryType {
id: string;
name: string;
type: string;
parentId: string;
orderBy: string;
remark: string;
delFlag?: string;
createTime?: string;
updateTime?: string;
createBy?: string;
updateBy?: string;
key?: string;
children?: CategoryType[];
}
// 友情链接类型定义
interface LinkType {
id: string;
classificationId: string;
name: string;
nameEn: string;
thumbnail: string;
url: string;
status: string;
orderBy: string;
createTime?: string;
updateTime?: string;
categoryName?: string; // 用于显示
// 以下是详情接口返回的额外字段
createBy?: string;
createDate?: string | null;
updateBy?: string | null;
updateDate?: string | null;
tenantId?: string | null;
tenantName?: string | null;
deleteFlag?: string | null;
lastUpdateTime?: string | null;
delFlag?: string;
remark?: string | null;
basePageRequest?: null;
}
// 友情链接分类请求参数
export interface CategoryRequest {
id?: string;
name: string;
type: string;
parentId: string;
orderBy: string;
remark: string;
}
// 友情链接分类响应数据
export interface CategoryItem {
id: string;
name: string;
type: string;
parentId: string;
orderBy: string;
remark: string;
delFlag: string;
createTime: string;
updateTime: string;
createBy: string;
updateBy?: string;
}
// 友情链接请求参数
export interface LinkRequest {
id?: string | number;
classificationId: string;
name: string;
nameEn: string;
thumbnail: string;
url: string;
orderBy: number | string;
}
// 友情链接响应数据
export interface LinkItem {
id: string;
classificationId: string;
name: string;
nameEn: string;
thumbnail: string;
url: string;
status: string;
orderBy: string;
delFlag: string;
createTime: string;
updateTime: string;
createBy: string;
updateBy?: string;
remark?: string;
basePageRequest?: null;
}
//
// 供应商评价任务状态枚举
export enum TaskStatus {
DRAFT = '0', // 草稿
@ -612,6 +259,285 @@ declare namespace API {
timeRange?: [string, string];
[property: string]: any;
}
// 供应商评价结果详情查询请求
export interface EvaluateSupplierRequest {
basePageRequest: BasePageRequest;
evaluateTaskId: string;
isAnswer?: number;
supplierName?: string;
level?: string;
[property: string]: any;
}
// 供应商评价结果详情响应数据
export interface EvaluateSupplierData {
countId: null;
current: number;
hitCount: boolean;
maxLimit: null;
optimizeCountSql: boolean;
orders: any[];
pages: number;
records: EvaluateSupplierRecord[];
searchCount: boolean;
size: number;
total: number;
[property: string]: any;
}
// 供应商评价结果详情记录
export interface EvaluateSupplierRecord {
basePageRequest: null;
createBy: string;
createDate: null;
createTime: string;
deleteFlag: null;
delFlag: string;
evaluateTaskId: string;
id: string;
lastUpdateTime: null;
reviewResult: null | string;
reviewScore: null | number;
supplierId: string;
tenantId: null;
tenantName: null;
updateBy: string;
updateDate: null;
updateTime: string;
supplierName?: string; // 供应商名称
category?: string; // 品类
level?: string; // 评价等级
score?: number; // 评价得分
[property: string]: any;
}
// 供应商评价结果详情查询参数
export interface EvaluateSupplierSearchParams {
evaluateTaskId?: string;
supplierName?: string;
level?: string;
[property: string]: any;
}
// 供应商评价打分情况请求
export interface EvaluateScoreRequest {
basePageRequest: BasePageRequest;
taskId: string;
supplierId: string;
[property: string]: any;
}
// 供应商评价打分情况响应数据
export interface EvaluateScoreData {
categoryId: null;
categoryLimitation: string;
createBy: null;
createDate: null;
createTime: null;
deleteFlag: null;
delFlag: string;
deptId: null;
endTime: string;
evaluateTheme: string;
evaluateYear: string;
id: string;
indicatorList: EvaluateScoreIndicator[];
lastUpdateTime: null;
startTime: string;
status: string;
supplierIds: EvaluateSupplierId[];
templateId: string;
tenantId: null;
tenantName: null;
updateBy: null;
updateDate: null;
updateTime: null;
weightDept: null;
weightStatus: string;
weightValue: null;
[property: string]: any;
}
// 评价指标列表
export interface EvaluateScoreIndicator {
indicatorIds: null[];
type: string;
userId: string;
userName?: string;
evaluateUnit?: string;
evaluateTime?: string;
score?: string | number;
[property: string]: any;
}
// 供应商ID列表
export interface EvaluateSupplierId {
id: string;
userIds: any[];
supplierName?: string;
category?: string;
[property: string]: any;
}
// 供应商评价打分情况查询参数
export interface EvaluateScoreSearchParams {
supplierName?: string;
evaluateUnit?: string;
level?: string;
[property: string]: any;
}
// 供应商评价打分详情查询请求
export interface EvaluateScoreDetailRequest {
id: string;
[property: string]: any;
}
// 供应商评价打分详情响应数据
export interface EvaluateScoreDetailData {
taskIndicatorVo?: {
baseIndicator: string; // 一级指标名称
indicatorDesc?: string; // 指标说明
score: string; // 一级指标分值
subIndicator?: {
id: string; // 二级指标ID
subIndicator: string; // 二级指标名称
subScore: string; // 二级指标分值
starIndicator?: string; // 是否星号项
scoreNum?: string; // 实际得分
remark?: string; // 评分说明
}[];
}[];
// 其他字段...
}
// 评价指标数据
export interface TaskIndicatorVo {
baseIndicator: string;
indicatorDesc: string;
score: string;
subIndicator: SubIndicator[];
[property: string]: any;
}
// 二级指标数据
export interface SubIndicator {
id: string;
remark: null;
scoreNum: null;
starIndicator: string;
stId: string;
subIndicator: string;
subScore: string;
[property: string]: any;
}
// 评价规则相关类型定义
export interface EvaluateRuleResponse {
code: number;
data: EvaluateRuleItem[];
message: string;
success: boolean;
[property: string]: any;
}
export interface EvaluateRuleDetailResponse {
code: number;
data: EvaluateRuleItem;
message: string;
success: boolean;
[property: string]: any;
}
export interface EvaluateRuleItem {
beginValue: string;
createBy: string;
createDate: null;
createTime: string;
deleteFlag: null;
delFlag: string;
endValue: string;
id: string;
lastUpdateTime: null;
levelName: string;
remark: string;
ratingName?: string;
tenantId: null;
tenantName: null;
updateBy: string;
updateDate: null;
updateTime: string;
[property: string]: any;
}
export interface EvaluateRuleAddRequest {
/**
* 阈值起始区间值
*/
beginValue: string;
/**
* 阈值截至区间值
*/
endValue: string;
/**
* 等级名称A、B、C...
*/
levelName: string;
/**
* 评级名称(优秀供应商、良好供应商、应辅导供应商、应淘汰供应商)
*/
ratingName: string;
/**
* 备注
*/
remark?: string;
[property: string]: any;
}
export interface EvaluateRuleUpdateRequest {
/**
* 规则ID
*/
id: string;
/**
* 阈值起始区间值
*/
beginValue: string | number;
/**
* 阈值截至区间值
*/
endValue: string | number;
/**
* 等级名称A、B、C...
*/
levelName: string;
/**
* 备注
*/
remark?: string;
[property: string]: any;
}
// 评价打分详情数据
interface IndicatorDetailData {
category: string;
name: string;
taskIndicatorVo: {
baseIndicator: string;
indicatorDesc: string;
score: string;
subIndicator: {
id: string;
remark: string | null;
scoreNum: string | null;
starIndicator: string;
stId: string;
subIndicator: string;
subScore: string;
}[];
}[];
}
}
// 供应商评价模块类型定义