修复系统概览数据不准确的查询。修复交叉评查意见列表的数量查询。优化全局消息提示的层级。优化提交意见进行局部更新。

This commit is contained in:
2025-07-25 09:49:36 +08:00
parent 3dab54d551
commit ccd5cdf71e
29 changed files with 2444 additions and 1035 deletions
@@ -175,6 +175,7 @@ interface ReviewPointsListProps {
scoringProposals?: ScoringProposal[];
jwtToken?: string; // 添加JWT token参数
userInfo?: UserInfo; // 添加用户信息参数
onOpinionSubmitted?: (newProposal: ScoringProposal) => void; // 新增:意见提交成功后的回调
}
/**
@@ -433,12 +434,14 @@ export function ReviewPointsList({
onReviewPointSelect,
scoringProposals = [],
jwtToken,
userInfo
userInfo,
onOpinionSubmitted
}: ReviewPointsListProps) {
// 状态管理
const [searchText, setSearchText] = useState(''); // 搜索文本
const [statusFilter, setStatusFilter] = useState<string | null>(null); // 状态过滤
const [evaluationResultIds, setEvaluationResultIds] = useState<number[]>([]); // 评分提案的evaluation_result_id
const [localScoringProposals, setLocalScoringProposals] = useState<ScoringProposal[]>(scoringProposals); // 本地状态管理scoringProposals
const fetcher = useFetcher();
// 归一化 reviewPoints,确保每个点都有 id 字段
@@ -452,17 +455,21 @@ export function ReviewPointsList({
setNormalizedReviewPoints(norm);
}, [reviewPoints]);
// 在组件中使用scoringProposals(这里只是简单使用以避免linter警告)
// 将来可以用于显示相关的评分提案信息
// 同步外部scoringProposals到本地状态
useEffect(() => {
if (scoringProposals && scoringProposals.length > 0) {
// console.log('收到评分提案数据:', scoringProposals.length, '个提案');
setLocalScoringProposals(scoringProposals);
}, [scoringProposals]);
// 在组件中使用localScoringProposals
useEffect(() => {
if (localScoringProposals && localScoringProposals.length > 0) {
// console.log('收到评分提案数据:', localScoringProposals.length, '个提案');
// 获取提案的evaluation_result_id
const evaluationResultIds = scoringProposals.map(proposal => Number(proposal.evaluation_result_id));
const evaluationResultIds = localScoringProposals.map(proposal => Number(proposal.evaluation_result_id));
setEvaluationResultIds(evaluationResultIds);
// console.log('提案的evaluation_result_id:', evaluationResultIds);
}
}, [scoringProposals]);
}, [localScoringProposals]);
// 提出意见模态框相关状态
const [isOpinionModalOpen, setIsOpinionModalOpen] = useState(false);
@@ -618,14 +625,14 @@ export function ReviewPointsList({
* 打开意见列表模态框
*/
const handleOpenOpinionListModal = (reviewPoint: ReviewPoint) => {
console.log('查看reviewPoint', reviewPoint);
if (scoringProposals.length === 0) {
// console.log('查看reviewPoint', reviewPoint);
if (localScoringProposals.length === 0) {
toastService.warning('当前文件尚未有人提出过意见');
return;
}
setSelectedReviewPoint(reviewPoint);
setIsOpinionListModalOpen(true);
console.log('打开意见列表模态框');
// console.log('打开意见列表模态框');
// 直接传递reviewPoint的documentId,避免依赖状态更新
loadOpinionListData(1, 10, reviewPoint.documentId);
};
@@ -714,14 +721,14 @@ export function ReviewPointsList({
}
// 新增:详细打印每个校验条件
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);
// 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 (
@@ -741,12 +748,12 @@ export function ReviewPointsList({
}
// 打印所有关键数据
console.log('selectedReviewPoint:', selectedReviewPoint);
console.log('opinionForm:', opinionForm);
console.log('userInfo:', userInfo);
// console.log('selectedReviewPoint:', selectedReviewPoint);
// console.log('opinionForm:', opinionForm);
// console.log('userInfo:', userInfo);
// 组装后端要求的字段名和内容
const data: Record<string, any> = {
const data = {
document_id: Number(selectedReviewPoint.documentId),
evaluation_point_id: Number(selectedReviewPoint.pointId),
proposed_score: Number(opinionForm.deductionScore),
@@ -759,10 +766,10 @@ export function ReviewPointsList({
data.evaluation_result_id = Number(selectedReviewPoint.evaluationPointId);
}
// 打印最终请求体
console.log('最终请求体:', data);
// console.log('最终请求体:', data);
// 用原生 fetch + application/json 提交
try {
const response = await fetch(`${API_BASE_URL.replace(/\/$/, '')}/admin/cross_review/proposals`, {
const response = await fetch(`${API_BASE_URL.value.replace(/\/$/, '')}/admin/cross_review/proposals`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -773,6 +780,28 @@ export function ReviewPointsList({
const result = await response.json();
if (response.ok) {
toastService.success('意见提交成功');
// 创建新的提案对象
const newProposal: ScoringProposal = {
id: result.id || Date.now(), // 使用返回的ID或时间戳作为临时ID
evaluation_result_id: data.evaluation_result_id,
proposer_id: data.proposer_id as number,
proposed_score: data.proposed_score,
reason: data.reason,
status: 'pending', // 默认状态
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
document_id: data.document_id
};
// 更新本地状态
setLocalScoringProposals(prev => [...prev, newProposal]);
// 调用父组件回调(如果提供)
if (onOpinionSubmitted) {
onOpinionSubmitted(newProposal);
}
handleCloseOpinionModal();
} else {
toastService.error(result.detail || '提交意见失败');
@@ -2487,7 +2516,7 @@ export function ReviewPointsList({
</button>
<button
className="px-4 py-2 bg-green-700 border border-transparent rounded-md text-sm font-medium text-white hover:bg-green-600 disabled:opacity-50"
onClick={handleSubmitOpinion}
onClick={() => handleSubmitOpinion()}
disabled={isSubmittingOpinion}
>
{isSubmittingOpinion ? '提交中...' : '发起投票'}
@@ -2652,7 +2681,7 @@ export function ReviewPointsList({
{
title: "投票人",
key: "votes",
width: "25%",
width: "22%",
align: "center" as const,
render: (_: unknown, record: CrossCheckingOpinion) => {
// 投票类型配置
@@ -2707,9 +2736,9 @@ export function ReviewPointsList({
{
title: "意见发起人",
key: "proposer",
width: "4%",
width: "8%",
render: (_: unknown, record: CrossCheckingOpinion) => (
<div className="flex items-center justify-center">
<div className="flex items-center justify-center text-left">
<span
className="px-1.5 py-0.5 rounded text-xs font-medium text-yellow-700 bg-yellow-100 border border-yellow-200 whitespace-nowrap overflow-hidden text-ellipsis max-w-[80px] transition-all hover:scale-[1.03] hover:shadow-sm"
>
@@ -2721,7 +2750,7 @@ export function ReviewPointsList({
{
title: "发起时间",
key: "created_at",
width: "18%",
width: "12%",
render: (_: unknown, record: CrossCheckingOpinion) => (
<div className="text-sm text-left">{record.created_at}</div>
)
@@ -2729,7 +2758,7 @@ export function ReviewPointsList({
{
title: "投票状态",
key: "opinion_status",
width: "10%",
width: "12%",
render: (_: unknown, record: CrossCheckingOpinion) => {
let label = '';
let color = '';
@@ -2754,7 +2783,7 @@ export function ReviewPointsList({
{
title: "操作",
key: "operation",
width: "18%",
width: "auto",
align: "center" as const,
render: (_: unknown, record: CrossCheckingOpinion) => {
const isPerforming = (action: string) => performingAction === `${record.proposal_id}-${action}`;
@@ -2869,7 +2898,7 @@ function OpinionActions({ record, isPerforming, handleOpinionAction, userInfo }:
</>
)}
{/* 仅当can_vote为false时显示撤销投票按钮 */}
{!record.can_vote && (
{!record.can_vote && !isProposer && (
<Button
type="default"
className="bg-yellow-600 hover:bg-yellow-700 text-white min-w-[80px] h-14 text-base font-medium rounded-lg flex items-center justify-center whitespace-nowrap shadow-md hover:shadow-lg transition-all duration-200 px-4 py-3"