评价打分
This commit is contained in:
@ -44,14 +44,7 @@ const SupplierEvaluateResultInfo: React.FC = () => {
|
||||
);
|
||||
const [evaluateRules, setEvaluateRules] = useState<API.EvaluateRuleItem[]>([]);
|
||||
|
||||
// 品类数据
|
||||
const categoryOptions = [
|
||||
{ label: '食品', value: '食品' },
|
||||
{ label: '电子', value: '电子' },
|
||||
{ label: '机械', value: '机械' },
|
||||
{ label: '化工', value: '化工' },
|
||||
{ label: '医药', value: '医药' },
|
||||
];
|
||||
|
||||
|
||||
// 获取上级页面传递的数据
|
||||
useEffect(() => {
|
||||
|
@ -6,7 +6,8 @@
|
||||
margin-bottom: 16px;
|
||||
|
||||
.titleSection {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.pageTitle {
|
||||
margin-bottom: 0;
|
||||
@ -15,7 +16,41 @@
|
||||
|
||||
.actionSection {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.submitButtonContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
:global {
|
||||
.filter-action-row {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-form {
|
||||
.filter-btns {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-area {
|
||||
background-color: #fff;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add styles for the tables */
|
||||
:global(.ant-table) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* Add styles for the tabs */
|
||||
:global(.ant-tabs-nav) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
@ -1,203 +1,453 @@
|
||||
// 供应商评价打分
|
||||
import React, { useState, useEffect } from 'react';
|
||||
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 {
|
||||
Button,
|
||||
Form,
|
||||
message,
|
||||
Typography,
|
||||
Space,
|
||||
Tabs,
|
||||
Input,
|
||||
DatePicker,
|
||||
Select,
|
||||
Table,
|
||||
} from 'antd';
|
||||
import { SearchOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { history } from 'umi';
|
||||
import styles from './supplierEvaluateScore.less';
|
||||
import { getSupplierScoreDetail, submitEvaluateScore } from '@/servers/api/supplierEvaluate';
|
||||
import {
|
||||
getSupplierDimension,
|
||||
getTaskPage,
|
||||
} from '@/servers/api/supplierEvaluate';
|
||||
|
||||
const { Title } = Typography;
|
||||
const { TabPane } = Tabs;
|
||||
const { RangePicker } = DatePicker;
|
||||
const { Option } = Select;
|
||||
|
||||
const SupplierEvaluateScore: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
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 [filterForm] = Form.useForm();
|
||||
// 新增状态
|
||||
const [activeTab, setActiveTab] = useState<string>('supplier');
|
||||
const [supplierTableData, setSupplierTableData] = useState<
|
||||
supplierEvaluateScore.SupplierDimensionRecord[]
|
||||
>([]);
|
||||
const [taskTableData, setTaskTableData] = useState<supplierEvaluateScore.TaskPageRecord[]>([]);
|
||||
const [supplierTableLoading, setSupplierTableLoading] = useState<boolean>(false);
|
||||
const [taskTableLoading, setTaskTableLoading] = useState<boolean>(false);
|
||||
const [pagination, setPagination] = useState({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// 获取上级页面传递的数据
|
||||
useEffect(() => {
|
||||
if (location.state?.record) {
|
||||
setSupplierRecord(location.state.record);
|
||||
}
|
||||
if (location.state?.parentRecord) {
|
||||
setParentRecord(location.state.parentRecord);
|
||||
}
|
||||
}, [location]);
|
||||
// 构建查询参数
|
||||
const buildQueryParams = () => {
|
||||
const values = filterForm.getFieldsValue();
|
||||
|
||||
// 将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 || ''
|
||||
};
|
||||
}) || []
|
||||
if (activeTab === 'supplier') {
|
||||
const params: supplierEvaluateScore.SupplierDimensionRequest = {
|
||||
basePageRequest: {
|
||||
pageNo: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
},
|
||||
keyword: values.keyword || undefined,
|
||||
status: values.status || undefined,
|
||||
};
|
||||
|
||||
// 处理时间范围
|
||||
if (values.evaluationTime && values.evaluationTime.length === 2) {
|
||||
params.startTime = values.evaluationTime[0].format('YYYY-MM-DD');
|
||||
params.endTime = values.evaluationTime[1].format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
return params;
|
||||
} else {
|
||||
const params: supplierEvaluateScore.TaskPageRequest = {
|
||||
basePageRequest: {
|
||||
pageNo: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
},
|
||||
keyword: values.keyword || undefined,
|
||||
status: values.status || undefined,
|
||||
};
|
||||
|
||||
// 处理时间范围
|
||||
if (values.evaluationTime && values.evaluationTime.length === 2) {
|
||||
params.startTime = values.evaluationTime[0].format('YYYY-MM-DD');
|
||||
params.endTime = values.evaluationTime[1].format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取供应商维度列表
|
||||
const fetchSupplierDimensionList = async (params: any) => {
|
||||
setSupplierTableLoading(true);
|
||||
try {
|
||||
const response = await getSupplierDimension(params);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setSupplierTableData(response.data.records || []);
|
||||
setPagination({
|
||||
...pagination,
|
||||
current: response.data.current || 1,
|
||||
total: response.data.total || 0,
|
||||
});
|
||||
} else {
|
||||
message.error(response.message || '获取供应商列表失败');
|
||||
setSupplierTableData([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取供应商列表失败:', error);
|
||||
message.error('获取供应商列表失败');
|
||||
setSupplierTableData([]);
|
||||
} finally {
|
||||
setSupplierTableLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取任务列表
|
||||
const fetchTaskList = async (params: any) => {
|
||||
setTaskTableLoading(true);
|
||||
try {
|
||||
const response = await getTaskPage(params);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setTaskTableData(response.data.records || []);
|
||||
setPagination({
|
||||
...pagination,
|
||||
current: response.data.current || 1,
|
||||
total: response.data.total || 0,
|
||||
});
|
||||
} else {
|
||||
message.error(response.message || '获取任务列表失败');
|
||||
setTaskTableData([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败:', error);
|
||||
message.error('获取任务列表失败');
|
||||
setTaskTableData([]);
|
||||
} finally {
|
||||
setTaskTableLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理搜索按钮点击
|
||||
const handleSearch = async () => {
|
||||
const params = buildQueryParams();
|
||||
|
||||
if (activeTab === 'supplier') {
|
||||
fetchSupplierDimensionList(params);
|
||||
} else {
|
||||
fetchTaskList(params);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化加载数据
|
||||
useEffect(() => {
|
||||
handleSearch();
|
||||
}, [activeTab]);
|
||||
|
||||
// 处理标签页切换
|
||||
const handleTabChange = (key: string) => {
|
||||
setActiveTab(key);
|
||||
setPagination({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
filterForm.resetFields();
|
||||
};
|
||||
|
||||
// 处理重置按钮点击
|
||||
const handleReset = () => {
|
||||
filterForm.resetFields();
|
||||
setPagination({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
// 处理分页变化
|
||||
const handleTableChange = (page: any) => {
|
||||
setPagination({
|
||||
...pagination,
|
||||
current: page.current,
|
||||
pageSize: page.pageSize,
|
||||
});
|
||||
|
||||
const params = buildQueryParams();
|
||||
params.basePageRequest.pageNo = page.current;
|
||||
params.basePageRequest.pageSize = page.pageSize;
|
||||
|
||||
if (activeTab === 'supplier') {
|
||||
fetchSupplierDimensionList(params);
|
||||
} else {
|
||||
fetchTaskList(params);
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到评分页面
|
||||
const goToScoring = (record: any, recordType: 'supplier' | 'task', mode: 'view' | 'score') => {
|
||||
// 构建路由状态参数
|
||||
const state: {
|
||||
record: any;
|
||||
mode: 'view' | 'score';
|
||||
recordType: 'supplier' | 'task';
|
||||
} = {
|
||||
record: record,
|
||||
mode,
|
||||
recordType: recordType,
|
||||
};
|
||||
if (recordType === 'task') {
|
||||
state.record.evaluateTaskId = record.id;
|
||||
history.push({
|
||||
pathname: '/supplierEvaluate/supplierEvaluateResultInfo',
|
||||
state: {record},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
history.push({
|
||||
pathname: '/supplierEvaluate/supplierEvaluateScoreDetail',
|
||||
state: state,
|
||||
});
|
||||
};
|
||||
|
||||
// 获取得分明细数据
|
||||
const fetchScoreDetail = async () => {
|
||||
if (!supplierRecord?.id) {
|
||||
message.error('缺少必要参数,无法获取数据');
|
||||
// 导出功能
|
||||
const handleExport = async (record: any) => {
|
||||
if (!record?.id) {
|
||||
message.error('缺少必要参数,无法导出');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await getSupplierScoreDetail(supplierRecord.id);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setScoreDetail(response.data);
|
||||
|
||||
// 转换数据格式
|
||||
const formattedData = formatDataForScoreTable(response.data);
|
||||
setScoreData(formattedData);
|
||||
} else {
|
||||
message.error(response.message || '获取评价得分明细失败');
|
||||
}
|
||||
window.open(
|
||||
`${SERVER_BASE}/coscoEvaluate/supplier/export?evaluateTaskId=${record.id}`,
|
||||
'_blank',
|
||||
'noopener,noreferrer',
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('获取评价得分明细失败:', error);
|
||||
message.error('获取评价得分明细失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
console.error('导出失败:', error);
|
||||
message.error('导出失败,请稍后再试');
|
||||
}
|
||||
};
|
||||
|
||||
// 当供应商记录加载完成后,获取得分明细
|
||||
useEffect(() => {
|
||||
if (supplierRecord?.id) {
|
||||
fetchScoreDetail();
|
||||
}
|
||||
}, [supplierRecord]);
|
||||
// 供应商Tab的表格列
|
||||
const supplierColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
render: (_: any, __: any, index: number) =>
|
||||
(pagination.current - 1) * pagination.pageSize + index + 1,
|
||||
},
|
||||
{
|
||||
title: '供应商名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '评价主题',
|
||||
dataIndex: 'evaluateTheme',
|
||||
key: 'evaluateTheme',
|
||||
},
|
||||
{
|
||||
title: '发起单位',
|
||||
dataIndex: 'tenantName',
|
||||
key: 'tenantName',
|
||||
},
|
||||
{
|
||||
title: '评价开始时间',
|
||||
dataIndex: 'startTime',
|
||||
key: 'startTime',
|
||||
},
|
||||
{
|
||||
title: '评价结束时间',
|
||||
dataIndex: 'endTime',
|
||||
key: 'endTime',
|
||||
},
|
||||
{
|
||||
title: '评价状态',
|
||||
dataIndex: 'statusName',
|
||||
key: 'statusName',
|
||||
},
|
||||
{
|
||||
title: '提交状态',
|
||||
dataIndex: 'submissionStatus',
|
||||
key: 'submissionStatus',
|
||||
},
|
||||
{
|
||||
title: '提交时间',
|
||||
dataIndex: 'submissionTime',
|
||||
key: 'submissionTime',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text: string, record: any) => (
|
||||
<Space>
|
||||
<Button type="link" onClick={() => goToScoring(record, 'supplier', 'view')}>
|
||||
查看
|
||||
</Button>
|
||||
{record.status === '1' && ( // 只有待评分状态才显示打分按钮
|
||||
<Button type="link" onClick={() => goToScoring(record, 'supplier', 'score')}>
|
||||
打分
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
history.goBack();
|
||||
};
|
||||
// 评价任务Tab的表格列
|
||||
const taskColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
render: (_: any, __: any, index: number) =>
|
||||
(pagination.current - 1) * pagination.pageSize + index + 1,
|
||||
},
|
||||
{
|
||||
title: '评价主题',
|
||||
dataIndex: 'evaluateTheme',
|
||||
key: 'evaluateTheme',
|
||||
},
|
||||
{
|
||||
title: '发起单位',
|
||||
dataIndex: 'deptName',
|
||||
key: 'deptName',
|
||||
},
|
||||
{
|
||||
title: '评价开始时间',
|
||||
dataIndex: 'startTime',
|
||||
key: 'startTime',
|
||||
},
|
||||
{
|
||||
title: '评价结束时间',
|
||||
dataIndex: 'endTime',
|
||||
key: 'endTime',
|
||||
},
|
||||
{
|
||||
title: '评价状态',
|
||||
dataIndex: 'statusName',
|
||||
key: 'statusName',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text: string, record: any) => (
|
||||
<Space>
|
||||
<Button type="link" onClick={() => goToScoring(record, 'task', 'view')}>
|
||||
查看
|
||||
</Button>
|
||||
<Button type="link" onClick={() => handleExport(record)}>
|
||||
导出
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// 处理评分数据变更
|
||||
const handleScoreDataChange = (newData: any[]) => {
|
||||
setScoreData(newData);
|
||||
};
|
||||
// 筛选表单
|
||||
const renderFilterForm = () => (
|
||||
<div className="filter-action-row">
|
||||
<div className="filter-form">
|
||||
<Form form={filterForm} layout="inline">
|
||||
<Form.Item name="keyword" label="关键字">
|
||||
<Input
|
||||
placeholder={
|
||||
activeTab === 'supplier' ? '请输入供应商名称或评价主题' : '请输入评价主题'
|
||||
}
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
// 提交评分
|
||||
const handleSubmit = async () => {
|
||||
if (!supplierRecord?.id) {
|
||||
message.error('缺少必要参数,无法提交');
|
||||
return;
|
||||
}
|
||||
<Form.Item name="evaluationTime" label="评价时间">
|
||||
<RangePicker />
|
||||
</Form.Item>
|
||||
|
||||
// 验证所有二级指标是否都已评分
|
||||
const hasEmptyScore = scoreData.some(item =>
|
||||
item.indicatorNdList.some((subItem: any) =>
|
||||
!subItem.actualScore && subItem.actualScore !== 0
|
||||
)
|
||||
);
|
||||
<Form.Item name="status" label="评价状态">
|
||||
<Select placeholder="请选择" style={{ width: 150 }} allowClear>
|
||||
<Option value="1">待评分</Option>
|
||||
<Option value="2">已评分</Option>
|
||||
<Option value="3">进行中</Option>
|
||||
<Option value="4">已完成</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
if (hasEmptyScore) {
|
||||
message.warning('请为所有指标填写评分');
|
||||
return;
|
||||
}
|
||||
|
||||
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 response = await submitEvaluateScore(submitData);
|
||||
|
||||
if (response.success) {
|
||||
message.success('评分提交成功');
|
||||
// 提交成功后返回列表页
|
||||
history.goBack();
|
||||
} else {
|
||||
message.error(response.message || '评分提交失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('评分提交失败:', error);
|
||||
message.error('评分提交失败');
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
<Form.Item className="filter-btns">
|
||||
<Space>
|
||||
<Button type="primary" onClick={handleSearch}>
|
||||
<SearchOutlined /> 查询
|
||||
</Button>
|
||||
<Button onClick={handleReset} type="primary" danger>
|
||||
<DeleteOutlined /> 重置
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="common-container">
|
||||
<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"
|
||||
icon={<SaveOutlined />}
|
||||
onClick={handleSubmit}
|
||||
loading={submitting}
|
||||
>
|
||||
提交
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 筛选条件区域 */}
|
||||
{renderFilterForm()}
|
||||
|
||||
<div className="content-area">
|
||||
<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>
|
||||
<Tabs activeKey={activeTab} onChange={handleTabChange}>
|
||||
<TabPane tab="按供应商" key="supplier">
|
||||
<Table
|
||||
columns={supplierColumns}
|
||||
dataSource={supplierTableData}
|
||||
rowKey="id"
|
||||
loading={supplierTableLoading}
|
||||
pagination={{
|
||||
current: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
total: pagination.total,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
}}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</TabPane>
|
||||
<TabPane tab="按评价任务" key="task">
|
||||
<Table
|
||||
columns={taskColumns}
|
||||
dataSource={taskTableData}
|
||||
rowKey="id"
|
||||
loading={taskTableLoading}
|
||||
pagination={{
|
||||
current: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
total: pagination.total,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
}}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -0,0 +1,302 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { history, useLocation } from 'umi';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Descriptions,
|
||||
Divider,
|
||||
Spin,
|
||||
message,
|
||||
Typography,
|
||||
Empty,
|
||||
Space,
|
||||
Form,
|
||||
Modal,
|
||||
} from 'antd';
|
||||
import { ArrowLeftOutlined, SaveOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
import { getSupplierScoreDetail, saveEvaluateScore } from '@/servers/api/supplierEvaluate';
|
||||
import ScoreEvaluationTable from '@/components/ScoreEvaluationTable';
|
||||
import styles from './supplierEvaluateScore.less';
|
||||
|
||||
const { Title } = Typography;
|
||||
const { confirm } = Modal;
|
||||
|
||||
const SupplierEvaluateScoreDetail: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const location = useLocation<{
|
||||
record: supplierEvaluateScore.SupplierDimensionRecord | supplierEvaluateScore.TaskPageRecord;
|
||||
mode?: 'view' | 'score'; // 查看模式或打分模式
|
||||
recordType: 'supplier' | 'task'; // 记录类型:供应商或任务
|
||||
}>();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [submitting, setSubmitting] = useState<boolean>(false);
|
||||
const [saving, setSaving] = useState<boolean>(false);
|
||||
const [scoreDetail, setScoreDetail] = useState<supplierEvaluateScore.ScoreDetailData | null>(
|
||||
null,
|
||||
);
|
||||
const [scoreData, setScoreData] = useState<any[]>([]);
|
||||
const [record, setRecord] = useState<any>(null);
|
||||
const [mode, setMode] = useState<'view' | 'score'>('view'); // 默认为查看模式
|
||||
const [recordType, setRecordType] = useState<'supplier' | 'task'>('supplier'); // 默认为供应商类型
|
||||
|
||||
// 从路由获取传递的记录
|
||||
useEffect(() => {
|
||||
if (location.state?.record) {
|
||||
setRecord(location.state.record);
|
||||
|
||||
// 设置记录类型
|
||||
if (location.state.recordType) {
|
||||
setRecordType(location.state.recordType);
|
||||
}
|
||||
|
||||
// 设置模式
|
||||
if (location.state.mode) {
|
||||
setMode(location.state.mode);
|
||||
} else {
|
||||
// 如果没有传递mode,则根据状态判断
|
||||
setMode(location.state.record.status === '1' ? 'score' : 'view');
|
||||
}
|
||||
} else {
|
||||
message.error('缺少必要参数,无法获取详情');
|
||||
history.goBack();
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
// 将API数据转换为ScoreEvaluationTable组件所需的格式
|
||||
const formatDataForScoreTable = (data: supplierEvaluateScore.ScoreDetailData) => {
|
||||
if (!data?.taskIndicatorVo) return [];
|
||||
|
||||
return data.taskIndicatorVo.map((indicator) => {
|
||||
return {
|
||||
baseIndicator: indicator.baseIndicator,
|
||||
indicatorDesc: indicator.indicatorDesc,
|
||||
score: indicator.score,
|
||||
// 为ScoreEvaluationTable组件添加额外字段
|
||||
indicatorNdList:
|
||||
indicator.subIndicator
|
||||
?.map((subItem) => {
|
||||
// 确保subItem是一个对象,而不是直接渲染
|
||||
if (typeof subItem !== 'object' || subItem === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: subItem.id,
|
||||
subIndicator: subItem.subIndicator,
|
||||
score: subItem.subScore,
|
||||
isStar: subItem.starIndicator,
|
||||
actualScore: subItem.scoreNum || '',
|
||||
remark: subItem.remark || '',
|
||||
};
|
||||
})
|
||||
.filter(Boolean) || [],
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// 获取评价打分详情
|
||||
const fetchScoreDetail = async () => {
|
||||
if (!record?.id) {
|
||||
message.error('缺少必要参数,无法获取数据');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await getSupplierScoreDetail(record.id);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setScoreDetail(response.data);
|
||||
|
||||
// 转换数据格式
|
||||
const formattedData = formatDataForScoreTable(response.data);
|
||||
setScoreData(formattedData);
|
||||
} else {
|
||||
message.error(response.message || '获取评价得分明细失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取评价得分明细失败:', error);
|
||||
message.error('获取评价得分明细失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 当记录加载完成后,获取得分明细
|
||||
useEffect(() => {
|
||||
if (record?.id) {
|
||||
fetchScoreDetail();
|
||||
}
|
||||
}, [record]);
|
||||
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
history.goBack();
|
||||
};
|
||||
|
||||
// 处理评分数据变更
|
||||
const handleScoreDataChange = (newData: any[]) => {
|
||||
setScoreData(newData);
|
||||
};
|
||||
|
||||
// 提交评分
|
||||
const handleSubmit = async () => {
|
||||
if (!record?.id) {
|
||||
message.error('缺少必要参数,无法提交');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证所有二级指标是否都已评分
|
||||
const hasEmptyScore = scoreData.some((item) =>
|
||||
item.indicatorNdList.some((subItem: any) => !subItem.scoreNum && subItem.scoreNum !== 0),
|
||||
);
|
||||
|
||||
if (hasEmptyScore) {
|
||||
message.warning('请为所有指标填写评分');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示确认对话框
|
||||
confirm({
|
||||
title: '提交确认',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: '评分提交后将不可修改,确定要提交吗?',
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
setSubmitting(true);
|
||||
try {
|
||||
// 构建提交数据
|
||||
const submitData: supplierEvaluateScore.ScoreSaveRequest = {
|
||||
id: record.id,
|
||||
scoreVoList: scoreData.flatMap((item) => {
|
||||
return item.indicatorNdList.map((subItem: any) => ({
|
||||
id: item.id,
|
||||
remark: subItem.remark || item.remark || '',
|
||||
score: String(subItem.scoreNum || item.score || ''),
|
||||
}));
|
||||
}),
|
||||
};
|
||||
const response = await saveEvaluateScore(submitData);
|
||||
|
||||
if (response.success) {
|
||||
message.success('评分保存成功');
|
||||
history.goBack();
|
||||
} else {
|
||||
message.error(response.message || '评分保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('评分提交失败:', error);
|
||||
message.error('评分提交失败');
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 获取评价状态文本
|
||||
const getStatusText = (status: string) => {
|
||||
const statusMap: { [key: string]: string } = {
|
||||
'1': '待评分',
|
||||
'2': '已评分',
|
||||
'3': '进行中',
|
||||
'4': '已完成',
|
||||
};
|
||||
return statusMap[status] || '未知状态';
|
||||
};
|
||||
|
||||
// 获取供应商名称
|
||||
const getSupplierName = () => {
|
||||
if (recordType === 'supplier') {
|
||||
return record?.supplierName || record?.name || scoreDetail?.name || '-';
|
||||
} else {
|
||||
return scoreDetail?.name || '-';
|
||||
}
|
||||
};
|
||||
|
||||
// 获取评价主题
|
||||
const getEvaluateTheme = () => {
|
||||
return record?.evaluateTheme || '-';
|
||||
};
|
||||
|
||||
// 获取发起单位
|
||||
const getUnitName = () => {
|
||||
return record?.tenantName || record?.deptName || '-';
|
||||
};
|
||||
|
||||
// 判断是否可以编辑(只有打分模式才可编辑)
|
||||
const canEdit = mode === 'score';
|
||||
|
||||
return (
|
||||
<div className="common-container">
|
||||
<div className={styles.headerRow}>
|
||||
<div className={styles.titleSection}>
|
||||
<Title level={4} className={styles.pageTitle}>
|
||||
{getSupplierName()} - 评价打分
|
||||
</Title>
|
||||
</div>
|
||||
<div className={styles.actionSection}>
|
||||
<Button type="link" icon={<ArrowLeftOutlined />} onClick={handleBack}>
|
||||
返回
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Spin spinning={loading}>
|
||||
{scoreDetail ? (
|
||||
<div className="content-area">
|
||||
<Card title="基本信息" bordered={false}>
|
||||
<Descriptions column={2} bordered>
|
||||
<Descriptions.Item label="供应商名称">{getSupplierName()}</Descriptions.Item>
|
||||
<Descriptions.Item label="品类">{scoreDetail.category || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="评价主题">{getEvaluateTheme()}</Descriptions.Item>
|
||||
<Descriptions.Item label="评价状态">
|
||||
{getStatusText(record?.status || '') || '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="评价开始时间">
|
||||
{record?.startTime || '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="评价结束时间">{record?.endTime || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="发起单位">{getUnitName()}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Card title="评价打分" bordered={false}>
|
||||
{scoreData.length > 0 ? (
|
||||
<ScoreEvaluationTable
|
||||
value={scoreData}
|
||||
onChange={handleScoreDataChange}
|
||||
isDetail={!canEdit} // 如果不可编辑,则以只读方式显示
|
||||
/>
|
||||
) : (
|
||||
<Empty description="暂无评分数据" />
|
||||
)}
|
||||
|
||||
{/* 只在打分模式下显示提交按钮,并移至底部 */}
|
||||
{canEdit && (
|
||||
<div className={styles.submitButtonContainer}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SaveOutlined />}
|
||||
onClick={handleSubmit}
|
||||
loading={submitting}
|
||||
style={{ marginTop: 24 }}
|
||||
>
|
||||
提交评分
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
) : (
|
||||
!loading && <Empty description="暂无评分数据" />
|
||||
)}
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SupplierEvaluateScoreDetail;
|
Reference in New Issue
Block a user