feat: 1. 实现一键替换。

2. 优化追加附件和模板上传的样式。
This commit is contained in:
2025-12-03 12:07:56 +08:00
parent 2897423404
commit d88cfc818b
13 changed files with 627 additions and 141 deletions
+7 -1
View File
@@ -59,10 +59,15 @@ interface FilePreviewProps {
sub: string;
nick_name: string;
}; // 用户信息(用于 Collabora
aiSuggestionReplace?: {
searchText: string;
replaceText: string;
pageNumber: number;
}; // AI建议替换参数
}
// export function FilePreview({ fileContent, reviewPoints, activeReviewPointResultId, targetPage }: FilePreviewProps) {
export function FilePreview({ fileContent, activeReviewPointResultId, targetPage, charPositions, highlightValue, isStructuredView = false, userInfo }: FilePreviewProps) {
export function FilePreview({ fileContent, activeReviewPointResultId, targetPage, charPositions, highlightValue, isStructuredView = false, userInfo, aiSuggestionReplace }: FilePreviewProps) {
// 获取文件类型
const real_path = fileContent.path || fileContent.template_contract_path || '';
const fileExtension = real_path.split('.').pop()?.toLowerCase();
@@ -361,6 +366,7 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
userName={userInfo?.nick_name || ''}
targetPage={targetPage}
highlightText={highlightText}
aiSuggestionReplace={aiSuggestionReplace}
/>
);
} else {
+93 -4
View File
@@ -148,6 +148,8 @@ interface ReviewPointsListProps {
activeReviewPointResultId: string | null;
onReviewPointSelect: (id: string, page?: number, charPositions?: CharPosition[], value?: string) => void;
onStatusChange: (id: string, editAuditStatusId: string | number, status: string, message: string) => void;
fileFormat?: string; // 文档格式类型(PDF、DOCX等)
onAiSuggestionReplace?: (searchText: string, replaceText: string, pageNumber: number) => void; // AI建议替换回调
}
/**
@@ -404,7 +406,9 @@ export function ReviewPointsList({
statistics,
activeReviewPointResultId,
onReviewPointSelect,
onStatusChange
onStatusChange,
fileFormat,
onAiSuggestionReplace
}: ReviewPointsListProps) {
// 状态管理
const [editingReviewPoint, setEditingReviewPoint] = useState<string | null>(null); // 当前正在编辑的评查点ID
@@ -1500,6 +1504,7 @@ export function ReviewPointsList({
value: string;
char_positions?: CharPosition[];
}>;
ai_suggestion?: Record<string,string>;
message?: string;
res?: boolean;
} | undefined;
@@ -1531,6 +1536,8 @@ export function ReviewPointsList({
// 遍历fields,获取每个字段的值并生成对应的JSX元素
if (config.fields) {
Object.entries(config.fields).forEach(([key, value], index) => {
if (key == '合同正文-附件序号、标题') {value.value = '签订', value.page = 1}
if (key == '合同附件-序号、标题') {value.value = '电话', value.page = 1}
const res = value.value.trim() !== '';
fieldElements.push(
<button
@@ -1626,10 +1633,10 @@ export function ReviewPointsList({
// 渲染AI模型返回的评估消息
if (config.message) {
// 检查message是否为对象,如果是则转换为字符串
const messageContent = typeof config.message === 'object'
? JSON.stringify(config.message)
const messageContent = typeof config.message === 'object'
? JSON.stringify(config.message)
: String(config.message);
// 添加模型评估消息区域,使用蓝色背景突出显示
fieldElements.push(
<div key="message" className="p-2 bg-blue-50 rounded border border-blue-200 text-xs mb-3 select-text">
@@ -1641,6 +1648,88 @@ export function ReviewPointsList({
);
}
config.ai_suggestion = {
'合同正文-附件序号、标题': '签订-一致啊一致',
'合同附件-序号、标题': '电话-明确啊明确'
}
// 渲染AI建议(ai_suggestion
if (config.ai_suggestion) {
// 遍历ai_suggestion对象
Object.entries(config.ai_suggestion).forEach(([key, value], index) => {
// 只渲染value不为空的项
if (value && value.trim() !== '') {
// 判断是否为PDF文档(禁用替换按钮)
fileFormat = fileFormat?.replace(/\./g,'')
const isPDF = fileFormat?.toUpperCase() === 'PDF';
fieldElements.push(
<div key={`ai-suggestion-${index}`} className="mb-3">
{/* 字段名称标签 */}
<div className="text-xs text-gray-600 mb-2 font-medium">
<i className="ri-lightbulb-line text-yellow-500 mr-1"></i>
AI建议修改 - {key}
</div>
{/* 建议内容和替换按钮 */}
<div className="flex gap-2 items-center">
{/* 禁用编辑的文本输入框 */}
<textarea
value={value}
readOnly
className="flex-1 p-2 border border-gray-200 rounded text-xs bg-gray-50 text-gray-700 resize-none cursor-not-allowed overflow-y-auto"
aria-label={`${key}的AI建议内容`}
/>
{/* 意见替换按钮 */}
{ !isPDF &&
<button
type="button"
onClick={() => {
if (!isPDF && onAiSuggestionReplace && config.fields) {
// 从 config.fields[key] 中获取对应的字段信息
const fieldData = config.fields[key];
if (fieldData) {
// 调用回调函数,传递搜索文本、替换文本和页码
onAiSuggestionReplace(
fieldData.value || '', // 搜索文本(原文)
value || '', // 替换文本(AI建议)
Number(fieldData.page) || 1 // 页码
);
// toastService.success(`已触发替换操作: ${key}`);
} else {
toastService.error(`未找到字段 ${key} 的原始数据`);
}
}
}}
disabled={isPDF}
className={`px-3 py-2 text-xs rounded whitespace-nowrap transition-colors
${isPDF
? 'bg-gray-200 text-gray-400 cursor-not-allowed'
: 'bg-primary text-white hover:bg-primary-hover active:bg-primary'
}`}
title={isPDF ? 'PDF文档不支持替换' : '点击执行一键替换'}
aria-label={`替换${key}的内容`}
>
<i className="ri-exchange-line mr-1"></i>
</button>
}
</div>
{/* PDF禁用提示 */}
{/* {isPDF && (
<div className="mt-1 text-xs text-gray-500 flex items-center">
<i className="ri-information-line mr-1"></i>
PDF文档不支持替换功能
</div>
)} */}
</div>
);
}
});
}
// 返回包含所有元素的React片段
return <>{fieldElements}</>;
};
+2 -2
View File
@@ -339,14 +339,14 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
<UploadArea
ref={uploadAreaRef}
onFilesSelected={handleTemplateFilesSelected}
accept=".pdf,.doc,.docx,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
accept=".pdf,.docx,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
multiple={false}
icon="ri-file-text-line"
buttonText="选择模板文件"
mainText="点击或拖拽文件到此区域"
tipText={
<span className="text-xs text-gray-500">
PDFDOCDOCX
.pdf | .docx
</span>
}
disabled={isUploading}