测通完成评查,投票,意见列表,任务列表,任务关联文档列表的内容。剩余创建任务,提出意见的完善
This commit is contained in:
@@ -23,11 +23,12 @@
|
||||
*/
|
||||
|
||||
import { type MetaFunction, type LoaderFunctionArgs, type ActionFunctionArgs } from "@remix-run/node";
|
||||
import { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate, useLoaderData } from "@remix-run/react";
|
||||
import crossCheckingStyles from "~/styles/cross-checking-result.css?url";
|
||||
import { getReviewPoints, updateReviewResult } from "~/api/evaluation_points/reviews";
|
||||
import { getReviewPoints, updateReviewResult} from "~/api/evaluation_points/reviews";
|
||||
import { toastService } from "~/components/ui/Toast";
|
||||
import { confirmReviewResults, checkProposalVotes, findIsProposer } from "~/api/cross-checking/cross-file-result";
|
||||
|
||||
// 导入交叉评查详情页面组件
|
||||
import {
|
||||
@@ -183,19 +184,26 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const id = url.searchParams.get('id') || undefined;
|
||||
const taskId = url.searchParams.get('tId') || undefined;
|
||||
const previousRoute = url.searchParams.get('previousRoute') || '';
|
||||
// console.log("id-------",id);
|
||||
if (!id) {
|
||||
return Response.json({ result: false, message: '文件ID不能为空' });
|
||||
}
|
||||
if (!taskId) {
|
||||
return Response.json({ result: false, message: '任务ID不能为空' });
|
||||
}
|
||||
|
||||
// 获取用户会话信息
|
||||
const { getUserSession } = await import("~/api/login/auth.server");
|
||||
const { frontendJWT } = await getUserSession(request);
|
||||
const { userInfo, frontendJWT } = await getUserSession(request);
|
||||
|
||||
// 获取评查点数据,传递request对象
|
||||
const reviewData = await getReviewPoints(id, request);
|
||||
|
||||
// 获取当前登录用户是否是发起人
|
||||
const isProposer = await findIsProposer(taskId, userInfo?.user_id);
|
||||
|
||||
// console.log("documentData-------",JSON.stringify(documentData.data,null,2));
|
||||
// console.log("reviewData-------",JSON.stringify('data' in reviewData ? reviewData.data : '',null,2));
|
||||
// console.log("reviewData-------",JSON.stringify(reviewData,null,2));
|
||||
@@ -215,7 +223,9 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
statistics: reviewData.stats,
|
||||
comparison_document: reviewData.comparison_document,
|
||||
scoring_proposals: reviewData.scoring_proposals || [],
|
||||
jwtToken: frontendJWT // 传递JWT token
|
||||
userInfo: userInfo,
|
||||
jwtToken: frontendJWT, // 传递JWT token
|
||||
isProposer: isProposer
|
||||
});
|
||||
} else {
|
||||
console.error("返回的评查数据格式不正确",JSON.stringify(reviewData,null,2));
|
||||
@@ -298,20 +308,9 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
}
|
||||
|
||||
if (intent === "confirmReviewResults") {
|
||||
toastService.error('确认评查结果功能暂未实现');
|
||||
// TODO 应该在cross-file-result.ts中新增一个确认的方法
|
||||
// const documentId = formData.get("documentId") as string;
|
||||
|
||||
// const response = await confirmReviewResults(documentId, request);
|
||||
|
||||
// if (response.error) {
|
||||
// return Response.json({ success: false, error: response.error }, { status: response.status || 500 });
|
||||
// }
|
||||
|
||||
// return Response.json({ success: true, data: response.data });
|
||||
// 检查文档下提案是否存在未投票用户,首先先打开一个模态框,提示用户是否确认完成评查,如果用户点击确认,则调用confirmReviewResults接口,如果用户点击取消,则关闭模态框
|
||||
// 模态框内的数据需要根据checkProposalVotes返回回来的数据进行显示,如果存在未投票用户,则提示用户存在未投票用户,如果不存在未投票用户,则提示用户完成评查
|
||||
}
|
||||
|
||||
return Response.json({ success: false, error: "未知的操作类型" }, { status: 400 });
|
||||
} catch (error) {
|
||||
console.error('Action处理失败:', error);
|
||||
return Response.json({
|
||||
@@ -324,7 +323,7 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
export default function CrossCheckingResult() {
|
||||
const navigate = useNavigate();
|
||||
const loaderData = useLoaderData<typeof loader>();
|
||||
const { document, reviewPoints, statistics, reviewInfo, scoring_proposals, jwtToken } = loaderData;
|
||||
const { document, reviewPoints, statistics, reviewInfo, scoring_proposals, jwtToken, userInfo, isProposer } = loaderData;
|
||||
const [isLoading, setIsLoading] = useState(false); // 已经通过loader加载了数据,不需要再显示加载状态
|
||||
const [reviewData, setReviewData] = useState<ReviewData | null>(null);
|
||||
const [activeReviewPointResultId, setActiveReviewPointResultId] = useState<string | null>(null);
|
||||
@@ -511,44 +510,90 @@ export default function CrossCheckingResult() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmResults = async () => {
|
||||
/**
|
||||
* 处理确认评查结果
|
||||
* 1. 检查未投票提案
|
||||
* 2. 根据结果弹出确认模态框
|
||||
* 3. 用户确认后更新文档状态并跳转
|
||||
*/
|
||||
const handleConfirmResults = async (event?: React.MouseEvent) => {
|
||||
// 阻止默认行为,防止页面刷新
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (!document || !document.id) {
|
||||
toastService.error('文档数据不完整,无法确认评查结果');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 显示加载状态
|
||||
setIsLoading(true);
|
||||
|
||||
// 使用 fetch 调用 action
|
||||
const formData = new FormData();
|
||||
formData.append("intent", "confirmReviewResults");
|
||||
formData.append("documentId", document.id.toString());
|
||||
|
||||
const response = await fetch(window.location.pathname, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
// 1. 先检查未投票
|
||||
const checkRes = await checkProposalVotes(document.id, jwtToken);
|
||||
console.log("checkRes", checkRes);
|
||||
|
||||
if (!result.success) {
|
||||
console.error('确认评查结果失败:', result.error);
|
||||
toastService.error(`确认评查结果失败: ${result.error}`);
|
||||
if (checkRes.error) {
|
||||
toastService.error(checkRes.error);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示成功消息
|
||||
toastService.success('评查结果已确认,文档审核状态已更新');
|
||||
// 2. 解析返回数据,定义明确的类型
|
||||
interface CheckProposalResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
data: {
|
||||
pending_proposals: Array<{
|
||||
evaluation_point_name: string;
|
||||
pending_voters_num: number;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
const responseData = checkRes.data as CheckProposalResponse;
|
||||
const pendingProposals = responseData?.data?.pending_proposals || [];
|
||||
console.log("pendingProposals", pendingProposals);
|
||||
|
||||
// 3. 构建模态框消息
|
||||
let modalMessage: string = '';
|
||||
if (Array.isArray(pendingProposals) && pendingProposals.length > 0) {
|
||||
modalMessage = pendingProposals.map((item) =>
|
||||
`评查名称为:${item.evaluation_point_name} 还剩余 ${item.pending_voters_num}人未投票。`
|
||||
).join('\n');
|
||||
} else {
|
||||
modalMessage = '是否完成评查?';
|
||||
}
|
||||
|
||||
// 4. 弹出模态框
|
||||
messageService.show({
|
||||
title: '提示',
|
||||
message: modalMessage,
|
||||
type: 'warning',
|
||||
confirmText: '确认',
|
||||
cancelText: '取消',
|
||||
onConfirm: async () => {
|
||||
setIsLoading(true);
|
||||
const res = await confirmReviewResults(document.id);
|
||||
setIsLoading(false);
|
||||
|
||||
if (res.error) {
|
||||
toastService.error(res.error);
|
||||
return;
|
||||
}
|
||||
|
||||
toastService.success('评查结果已确认,文档审核状态已更新');
|
||||
// 注释掉自动跳转,让用户停留在当前页面
|
||||
navigate('/cross-checking');
|
||||
}
|
||||
});
|
||||
|
||||
// 导航到交叉评查列表页
|
||||
navigate('/cross-checking');
|
||||
} catch (error) {
|
||||
console.error('确认评查结果出错:', error);
|
||||
toastService.error(`确认评查结果失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
} catch (error) {
|
||||
setIsLoading(false);
|
||||
toastService.error(`确认评查结果失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -608,13 +653,20 @@ export default function CrossCheckingResult() {
|
||||
</div>
|
||||
|
||||
{/* 完成评查按钮 */}
|
||||
<button
|
||||
onClick={handleConfirmResults}
|
||||
className="inline-flex items-center px-3 py-1.5 text-sm font-medium text-white bg-green-800 border border-transparent rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-800"
|
||||
>
|
||||
<i className="ri-check-double-line mr-1.5"></i>
|
||||
完成评查
|
||||
</button>
|
||||
{isProposer && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleConfirmResults(event);
|
||||
}}
|
||||
className="inline-flex items-center px-3 py-1.5 text-sm font-medium text-white bg-green-800 border border-transparent rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-800"
|
||||
>
|
||||
<i className="ri-check-double-line mr-1.5"></i>
|
||||
完成评查
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 文件信息和操作按钮 */}
|
||||
@@ -648,6 +700,7 @@ export default function CrossCheckingResult() {
|
||||
onStatusChange={handleReviewPointStatusChange}
|
||||
scoringProposals={scoring_proposals as ScoringProposal[]}
|
||||
jwtToken={jwtToken}
|
||||
userInfo={userInfo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user