适配交叉评查上传接口

修复N多个BUG
This commit is contained in:
2025-07-24 09:29:55 +08:00
parent 8800e982ab
commit 4934b083e3
6 changed files with 236 additions and 151 deletions
@@ -31,6 +31,7 @@ import {
type OpinionActionType
} from '../../api/cross-checking/cross-file-result';
import { useFetcher, useNavigate } from '@remix-run/react';
import { API_BASE_URL } from '~/config/api-config';
// import '../../styles/components/TooltipStyles.css';
/**
@@ -86,6 +87,7 @@ export interface ReviewPoint {
id: string;
documentId?: string;
pointId?: string;
evaluationPointId?: string | number; // 新增,允许兜底
editAuditStatusId?: string | number;
editAuditStatus: number;
editAuditStatusMessage?: string; // 添加审核意见字段
@@ -439,6 +441,17 @@ export function ReviewPointsList({
const [evaluationResultIds, setEvaluationResultIds] = useState<number[]>([]); // 评分提案的evaluation_result_id
const fetcher = useFetcher();
// 归一化 reviewPoints,确保每个点都有 id 字段
const [normalizedReviewPoints, setNormalizedReviewPoints] = useState<ReviewPoint[]>([]);
console.log('normalizedReviewPoints', normalizedReviewPoints);
useEffect(() => {
const norm = reviewPoints.map(point => ({
...point,
id: String(point.id || point.evaluationPointId || point.pointId || '') // 保证 id 为字符串且不为 undefined
}));
setNormalizedReviewPoints(norm);
}, [reviewPoints]);
// 在组件中使用scoringProposals(这里只是简单使用以避免linter警告)
// 将来可以用于显示相关的评分提案信息
useEffect(() => {
@@ -690,11 +703,6 @@ export function ReviewPointsList({
return;
}
if (opinionForm.deductionScore <= 0) {
toastService.error('扣分必须大于0');
return;
}
if (opinionForm.deductionScore > 100) {
toastService.error('扣分不能大于100分');
return;
@@ -705,26 +713,75 @@ export function ReviewPointsList({
return;
}
setIsSubmittingOpinion(true);
// 新增:详细打印每个校验条件
console.log('校验前 selectedReviewPoint:', selectedReviewPoint);
console.log('校验前 opinionForm:', opinionForm);
console.log('校验前 userInfo:', userInfo);
console.log('documentId:', selectedReviewPoint.documentId, 'isNaN:', isNaN(Number(selectedReviewPoint.documentId)), 'typeof:', typeof selectedReviewPoint.documentId);
console.log('pointId:', selectedReviewPoint.pointId, 'isNaN:', isNaN(Number(selectedReviewPoint.pointId)), 'typeof:', typeof selectedReviewPoint.pointId);
console.log('deductionScore:', opinionForm.deductionScore, 'typeof:', typeof opinionForm.deductionScore, 'isNaN:', isNaN(Number(opinionForm.deductionScore)));
console.log('auditOpinion:', opinionForm.auditOpinion, 'trim:', String(opinionForm.auditOpinion).trim(), 'typeof:', typeof opinionForm.auditOpinion);
console.log('user_id:', userInfo?.user_id, 'typeof:', typeof userInfo?.user_id);
// 更严谨的校验逻辑
if (
selectedReviewPoint.documentId === undefined ||
selectedReviewPoint.pointId === undefined ||
opinionForm.deductionScore === undefined ||
opinionForm.auditOpinion === undefined ||
userInfo?.user_id === undefined ||
isNaN(Number(selectedReviewPoint.documentId)) ||
isNaN(Number(selectedReviewPoint.pointId)) ||
isNaN(Number(opinionForm.deductionScore)) ||
!String(opinionForm.auditOpinion).trim()
) {
toastService.error('请完整填写所有必填项');
setIsSubmittingOpinion(false);
return;
}
// 打印所有关键数据
console.log('selectedReviewPoint:', selectedReviewPoint);
console.log('opinionForm:', opinionForm);
console.log('userInfo:', userInfo);
// 组装后端要求的字段名和内容
const data: Record<string, any> = {
document_id: Number(selectedReviewPoint.documentId),
evaluation_point_id: Number(selectedReviewPoint.pointId),
proposed_score: Number(opinionForm.deductionScore),
reason: opinionForm.auditOpinion,
proposer_id: userInfo.user_id,
problem_message: opinionForm.foundIssue,
evaluation_result_id: Number(selectedReviewPoint.id),
};
if (selectedReviewPoint.evaluationPointId) {
data.evaluation_result_id = Number(selectedReviewPoint.evaluationPointId);
}
// 打印最终请求体
console.log('最终请求体:', data);
// 用原生 fetch + application/json 提交
try {
// 使用 fetcher 调用路由的 action
const formData = new FormData();
formData.append("intent", "submitCrossCheckingOpinion");
formData.append("reviewPointResultId", selectedReviewPoint.id);
formData.append("documentId", selectedReviewPoint.documentId || '');
formData.append("auditPoint", opinionForm.auditPoint);
formData.append("foundIssue", opinionForm.foundIssue);
formData.append("auditOpinion", opinionForm.auditOpinion);
formData.append("deductionScore", opinionForm.deductionScore.toString());
fetcher.submit(formData, { method: "POST" });
const response = await fetch(`${API_BASE_URL.replace(/\/$/, '')}/admin/cross_review/proposals`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userInfo.frontend_jwt}`,
},
body: JSON.stringify(data)
});
const result = await response.json();
if (response.ok) {
toastService.success('意见提交成功');
handleCloseOpinionModal();
} else {
toastService.error(result.detail || '提交意见失败');
}
} catch (error) {
console.error('提交意见失败:', error);
toastService.error('提交意见失败,请稍后重试');
setIsSubmittingOpinion(false);
}
setIsSubmittingOpinion(false);
};
/**
@@ -2572,10 +2629,14 @@ export function ReviewPointsList({
{
title: "调整理由",
key: "reason",
width: "25%",
render: (_: unknown, record: CrossCheckingOpinion) => (
<div className="text-sm text-left">{record.reason}</div>
)
width: "15%",
render: (_: unknown, record: CrossCheckingOpinion) => {
const reason = record.reason || '';
const display = reason.length > 20 ? reason.slice(0, 20) + '...' : reason;
return (
<span title={reason}>{display}</span>
);
}
},
{
title: "调整分数",
@@ -2665,6 +2726,31 @@ export function ReviewPointsList({
<div className="text-sm text-left">{record.created_at}</div>
)
},
{
title: "投票状态",
key: "opinion_status",
width: "10%",
render: (_: unknown, record: CrossCheckingOpinion) => {
let label = '';
let color = '';
switch (record.status) {
case 'approved':
label = '通过';
color = 'text-green-600';
break;
case 'rejected':
label = '不通过';
color = 'text-red-600';
break;
case 'pending':
default:
label = '投票中';
color = 'text-yellow-600';
break;
}
return <span className={`font-bold ${color}`}>{label}</span>;
}
},
{
title: "操作",
key: "operation",