添加评查意见的悬浮按钮
This commit is contained in:
@@ -32,6 +32,7 @@ export interface CrossCheckingTask {
|
||||
status: CrossCheckingTaskStatus;
|
||||
score: number;
|
||||
operation: string;
|
||||
documentIds: number[];
|
||||
}
|
||||
|
||||
// API响应格式
|
||||
@@ -79,7 +80,8 @@ const mockTasks: CrossCheckingTask[] = [
|
||||
progress: 0,
|
||||
status: CrossCheckingTaskStatus.PENDING,
|
||||
score: 0,
|
||||
operation: '去评查'
|
||||
operation: '去评查',
|
||||
documentIds: [1, 2, 3, 4, 5]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
@@ -92,7 +94,8 @@ const mockTasks: CrossCheckingTask[] = [
|
||||
progress: 72,
|
||||
status: CrossCheckingTaskStatus.IN_PROGRESS,
|
||||
score: 0,
|
||||
operation: '进行中'
|
||||
operation: '进行中',
|
||||
documentIds: [1, 2, 3, 4, 5]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
@@ -105,7 +108,8 @@ const mockTasks: CrossCheckingTask[] = [
|
||||
progress: 100,
|
||||
status: CrossCheckingTaskStatus.COMPLETED,
|
||||
score: 95,
|
||||
operation: '查看结果'
|
||||
operation: '查看结果',
|
||||
documentIds: [1, 2, 3, 4, 5]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
@@ -118,7 +122,8 @@ const mockTasks: CrossCheckingTask[] = [
|
||||
progress: 100,
|
||||
status: CrossCheckingTaskStatus.COMPLETED,
|
||||
score: 85,
|
||||
operation: '查看结果'
|
||||
operation: '查看结果',
|
||||
documentIds: [1, 2, 3, 4, 5]
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
@@ -131,7 +136,8 @@ const mockTasks: CrossCheckingTask[] = [
|
||||
progress: 100,
|
||||
status: CrossCheckingTaskStatus.COMPLETED,
|
||||
score: 92,
|
||||
operation: '查看结果'
|
||||
operation: '查看结果',
|
||||
documentIds: [1, 2, 3, 4, 5]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ export async function getReviewPoints(fileId: string) {
|
||||
'document_id': `eq.${fileId}`
|
||||
}
|
||||
};
|
||||
const scoringProposalsResponse = await postgrestGet('scoring_proposals', scoringProposalsParams);
|
||||
const scoringProposalsResponse = await postgrestGet('cross_scoring_proposals', scoringProposalsParams);
|
||||
|
||||
if (scoringProposalsResponse.error) {
|
||||
return { error: scoringProposalsResponse.error, status: scoringProposalsResponse.status };
|
||||
@@ -404,8 +404,12 @@ export async function getReviewPoints(fileId: string) {
|
||||
// suggestion: '只是给建议的修改内容',
|
||||
|
||||
result: result.evaluated_results?.result, // 记录评查结果,用于统计
|
||||
// score是评查点设置的满分的分数
|
||||
score: point.score || 0,
|
||||
|
||||
// finalScore是评查点对应评查结果最终所得的分数 用户交叉评查时使用
|
||||
finalScore: result.final_score || 0,
|
||||
|
||||
postAction: point.post_action || '',
|
||||
// postAction: 'manual',
|
||||
|
||||
|
||||
@@ -416,12 +416,17 @@ export function ReviewPointsList({
|
||||
// 状态管理
|
||||
const [searchText, setSearchText] = useState(''); // 搜索文本
|
||||
const [statusFilter, setStatusFilter] = useState<string | null>(null); // 状态过滤
|
||||
const [evaluationResultIds, setEvaluationResultIds] = useState<number[]>([]); // 评分提案的evaluation_result_id
|
||||
|
||||
// 在组件中使用scoringProposals(这里只是简单使用以避免linter警告)
|
||||
// 将来可以用于显示相关的评分提案信息
|
||||
useEffect(() => {
|
||||
if (scoringProposals && scoringProposals.length > 0) {
|
||||
console.log('收到评分提案数据:', scoringProposals.length, '个提案');
|
||||
// 获取提案的evaluation_result_id
|
||||
const evaluationResultIds = scoringProposals.map(proposal => Number(proposal.evaluation_result_id));
|
||||
setEvaluationResultIds(evaluationResultIds);
|
||||
// console.log('提案的evaluation_result_id:', evaluationResultIds);
|
||||
}
|
||||
}, [scoringProposals]);
|
||||
|
||||
@@ -447,6 +452,11 @@ export function ReviewPointsList({
|
||||
* 打开提出意见模态框
|
||||
*/
|
||||
const handleOpenOpinionModal = (reviewPoint: ReviewPoint) => {
|
||||
// 如果评分提案的evaluation_result_id包含当前评查点的id,则不打开模态框
|
||||
if (evaluationResultIds.includes(Number(reviewPoint.id))) {
|
||||
toastService.error('当前评查点已有意见提出项,可前往意见列表查看');
|
||||
return;
|
||||
}
|
||||
setSelectedReviewPoint(reviewPoint);
|
||||
setOpinionForm({
|
||||
auditPoint: reviewPoint.pointName,
|
||||
@@ -2098,8 +2108,34 @@ export function ReviewPointsList({
|
||||
// 组件主渲染函数
|
||||
return (
|
||||
<>
|
||||
<div className="review-points-panel select-text">
|
||||
<TooltipPortal />
|
||||
<div className="relative">
|
||||
{/* 悬浮的意见数量显示 - 固定在左侧 */}
|
||||
<div className="absolute left-[-35px] top-16 z-10 group cursor-pointer">
|
||||
{/* 默认状态:竖向排列,窄宽度 */}
|
||||
<div className="flex flex-col items-center bg-blue-50 px-2 py-2 rounded-lg border border-blue-200 shadow-md transition-all duration-300 group-hover:scale-0 group-hover:opacity-0 origin-top-right">
|
||||
<i className="ri-chat-1-line text-blue-600 text-base"></i>
|
||||
<span className="text-base text-blue-600 font-bold leading-tight whitespace-nowrap">{scoringProposals.length}</span>
|
||||
<span className="text-xs text-blue-500 leading-tight whitespace-wrap">条</span>
|
||||
<span className="text-xs text-blue-500 leading-tight whitespace-wrap">意</span>
|
||||
<span className="text-xs text-blue-500 leading-tight whitespace-wrap">见</span>
|
||||
</div>
|
||||
|
||||
{/* 悬浮状态:横向排列,显示图标,数字放大 */}
|
||||
<div className="absolute top-0 right-0 opacity-0 scale-0 group-hover:opacity-100 group-hover:scale-100 flex items-center bg-blue-50 px-3 py-2 rounded-lg border border-blue-200 shadow-lg transition-all duration-300 origin-top-right">
|
||||
<button className="flex items-center" aria-label="点击查看详情">
|
||||
<div className="flex flex-col">
|
||||
<i className="ri-chat-1-line text-blue-600 text-base"></i>
|
||||
<span className="text-xl text-blue-600 font-bold">{scoringProposals.length}</span>
|
||||
<span className="text-xs text-blue-500 leading-tight whitespace-wrap">条</span>
|
||||
<span className="text-xs text-blue-500 leading-tight whitespace-wrap">意</span>
|
||||
<span className="text-xs text-blue-500 leading-tight whitespace-wrap">见</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="review-points-panel select-text">
|
||||
<TooltipPortal />
|
||||
{/* 面板头部 */}
|
||||
<div className="review-panel-header py-2 px-4 flex items-center">
|
||||
<i className="ri-file-list-check-line text-primary mr-2"></i>
|
||||
@@ -2126,7 +2162,7 @@ export function ReviewPointsList({
|
||||
tabIndex={0}
|
||||
style={{ userSelect: 'text' }}
|
||||
onClick={() => {
|
||||
// console.log('reviewPoint', reviewPoint);
|
||||
console.log('reviewPoint', reviewPoint);
|
||||
handleReviewPointClick(reviewPoint.id);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
@@ -2182,104 +2218,105 @@ export function ReviewPointsList({
|
||||
renderEmptyState()
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 提出意见模态框 */}
|
||||
<Modal
|
||||
isOpen={isOpinionModalOpen}
|
||||
onClose={handleCloseOpinionModal}
|
||||
title="提出意见"
|
||||
size="medium"
|
||||
footer={
|
||||
<div className="flex justify-end space-x-3">
|
||||
<button
|
||||
className="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||
onClick={handleCloseOpinionModal}
|
||||
disabled={isSubmittingOpinion}
|
||||
>
|
||||
取消
|
||||
</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}
|
||||
disabled={isSubmittingOpinion}
|
||||
>
|
||||
{isSubmittingOpinion ? '提交中...' : '发起投票'}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="space-y-4">
|
||||
{/* 审查点 */}
|
||||
<div>
|
||||
<label htmlFor="audit-point" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
审查点
|
||||
</label>
|
||||
<input
|
||||
id="audit-point"
|
||||
type="text"
|
||||
value={opinionForm.auditPoint}
|
||||
readOnly
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 text-sm focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 发现问题 */}
|
||||
<div>
|
||||
<label htmlFor="found-issue" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
发现问题
|
||||
</label>
|
||||
<input
|
||||
id="found-issue"
|
||||
type="text"
|
||||
value={opinionForm.foundIssue}
|
||||
readOnly
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 text-sm focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 审查意见 */}
|
||||
<div>
|
||||
<label htmlFor="audit-opinion" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
审查意见 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="audit-opinion"
|
||||
value={opinionForm.auditOpinion}
|
||||
onChange={(e) => handleOpinionFormChange('auditOpinion', e.target.value)}
|
||||
placeholder="请输入审查意见..."
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:ring-1 focus:ring-green-700 focus:border-green-700 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 扣分 */}
|
||||
<div>
|
||||
<label htmlFor="deduction-score" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
扣分 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="deduction-score"
|
||||
type="number"
|
||||
value={opinionForm.deductionScore}
|
||||
onChange={(e) => {
|
||||
const value = parseFloat(e.target.value);
|
||||
if (!isNaN(value) && value >= 0) {
|
||||
// 限制到1位小数
|
||||
const roundedValue = Math.round(value * 10) / 10;
|
||||
handleOpinionFormChange('deductionScore', roundedValue);
|
||||
}
|
||||
}}
|
||||
step="0.1"
|
||||
min="0"
|
||||
max="100"
|
||||
placeholder="0.0"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:ring-1 focus:ring-green-700 focus:border-green-700 focus:outline-none"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-gray-500">分数最多保留1位小数</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{/* 提出意见模态框 */}
|
||||
<Modal
|
||||
isOpen={isOpinionModalOpen}
|
||||
onClose={handleCloseOpinionModal}
|
||||
title="提出意见"
|
||||
size="medium"
|
||||
footer={
|
||||
<div className="flex justify-end space-x-3">
|
||||
<button
|
||||
className="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||
onClick={handleCloseOpinionModal}
|
||||
disabled={isSubmittingOpinion}
|
||||
>
|
||||
取消
|
||||
</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}
|
||||
disabled={isSubmittingOpinion}
|
||||
>
|
||||
{isSubmittingOpinion ? '提交中...' : '发起投票'}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="space-y-4">
|
||||
{/* 审查点 */}
|
||||
<div>
|
||||
<label htmlFor="audit-point" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
审查点
|
||||
</label>
|
||||
<input
|
||||
id="audit-point"
|
||||
type="text"
|
||||
value={opinionForm.auditPoint}
|
||||
readOnly
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 text-sm focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 发现问题 */}
|
||||
<div>
|
||||
<label htmlFor="found-issue" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
发现问题
|
||||
</label>
|
||||
<input
|
||||
id="found-issue"
|
||||
type="text"
|
||||
value={opinionForm.foundIssue}
|
||||
readOnly
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 text-sm focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 审查意见 */}
|
||||
<div>
|
||||
<label htmlFor="audit-opinion" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
审查意见 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="audit-opinion"
|
||||
value={opinionForm.auditOpinion}
|
||||
onChange={(e) => handleOpinionFormChange('auditOpinion', e.target.value)}
|
||||
placeholder="请输入审查意见..."
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:ring-1 focus:ring-green-700 focus:border-green-700 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 扣分 */}
|
||||
<div>
|
||||
<label htmlFor="deduction-score" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
扣分 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="deduction-score"
|
||||
type="number"
|
||||
value={opinionForm.deductionScore}
|
||||
onChange={(e) => {
|
||||
const value = parseFloat(e.target.value);
|
||||
if (!isNaN(value) && value >= 0) {
|
||||
// 限制到1位小数
|
||||
const roundedValue = Math.round(value * 10) / 10;
|
||||
handleOpinionFormChange('deductionScore', roundedValue);
|
||||
}
|
||||
}}
|
||||
step="0.1"
|
||||
min="0"
|
||||
max="100"
|
||||
placeholder="0.0"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:ring-1 focus:ring-green-700 focus:border-green-700 focus:outline-none"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-gray-500">分数最多保留1位小数</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -176,6 +176,11 @@ export default function CrossCheckingIndex() {
|
||||
return 'high';
|
||||
};
|
||||
|
||||
// 处理查看结果
|
||||
// const handleViewResult = (taskId: number, docIds: number[]) => {
|
||||
// // 根据taskId获取关联的
|
||||
// };
|
||||
|
||||
// 渲染进度条
|
||||
const renderProgress = (progress: number) => (
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -198,7 +203,7 @@ export default function CrossCheckingIndex() {
|
||||
type="primary"
|
||||
size="small"
|
||||
className="operation-btn primary"
|
||||
onClick={() => navigate(`/cross-checking/${task.id}`)}
|
||||
onClick={() => handleViewResult(task.id, task.documentIds)}
|
||||
>
|
||||
<i className="ri-play-line"></i>
|
||||
去评查
|
||||
@@ -210,7 +215,7 @@ export default function CrossCheckingIndex() {
|
||||
type="default"
|
||||
size="small"
|
||||
className="operation-btn secondary"
|
||||
onClick={() => navigate(`/cross-checking/${task.id}`)}
|
||||
onClick={() => handleViewResult(task.id, task.documentIds)}
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
进行中
|
||||
@@ -222,7 +227,7 @@ export default function CrossCheckingIndex() {
|
||||
type="default"
|
||||
size="small"
|
||||
className="operation-btn secondary"
|
||||
onClick={() => navigate(`/cross-checking/result?id=1355&previousRoute=cross-checking`)}
|
||||
onClick={() => handleViewResult(task.id, task.documentIds)}
|
||||
>
|
||||
<i className="ri-file-text-line"></i>
|
||||
查看结果
|
||||
|
||||
Reference in New Issue
Block a user