revert: reset to 32bee87 for clean text_bbox baseline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,3 @@ auth_doc/
|
|||||||
teach/
|
teach/
|
||||||
typecheck_result.txt
|
typecheck_result.txt
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
*.swp
|
|
||||||
run.log
|
|
||||||
package-lock.json
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import axios, { AxiosRequestConfig, AxiosResponse, isAxiosError } from 'axios';
|
import axios, { AxiosRequestConfig, AxiosResponse, isAxiosError } from 'axios';
|
||||||
import http from 'http';
|
|
||||||
import { mockData, type MockApiResponse } from './mock';
|
import { mockData, type MockApiResponse } from './mock';
|
||||||
import { API_BASE_URL, DOCUMENT_URL } from '../config/api-config';
|
import { API_BASE_URL, DOCUMENT_URL } from '../config/api-config';
|
||||||
import { toastService } from '../components/ui/Toast';
|
import { toastService } from '../components/ui/Toast';
|
||||||
@@ -42,9 +41,7 @@ const axiosInstance = axios.create({
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json'
|
||||||
},
|
}
|
||||||
// 修复 ECONNRESET: 禁用 keep-alive 复用,避免后端关闭空闲连接后前端仍复用导致 reset
|
|
||||||
httpAgent: new http.Agent({ keepAlive: false }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 请求白名单 - 这些接口不需要添加 Authorization 头
|
// 请求白名单 - 这些接口不需要添加 Authorization 头
|
||||||
|
|||||||
@@ -93,32 +93,6 @@ export interface CharPosition {
|
|||||||
score: number; // OCR识别置信度
|
score: number; // OCR识别置信度
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* text_bbox -> CharPosition[] 转换
|
|
||||||
* GraphRAG 抽取结果只有 text_bbox (段落级坐标), 没有 char_positions (字符级坐标)。
|
|
||||||
* 将 text_bbox 转为单个 CharPosition 矩形框, 让 PdfPreview 的高亮逻辑复用。
|
|
||||||
*/
|
|
||||||
function resolveCharPositions(data: any): CharPosition[] | undefined {
|
|
||||||
// 优先用 char_positions
|
|
||||||
if (data?.char_positions && data.char_positions.length > 0) {
|
|
||||||
return data.char_positions;
|
|
||||||
}
|
|
||||||
// fallback: text_bbox -> CharPosition[]
|
|
||||||
if (data?.text_bbox) {
|
|
||||||
const b = data.text_bbox;
|
|
||||||
if (b.x_min != null && b.y_min != null && b.x_max != null && b.y_max != null
|
|
||||||
&& (b.x_max - b.x_min) > 0 && (b.y_max - b.y_min) > 0) {
|
|
||||||
return [{
|
|
||||||
box: [[b.x_min, b.y_min], [b.x_max, b.y_min], [b.x_max, b.y_max], [b.x_min, b.y_max]],
|
|
||||||
char: '',
|
|
||||||
score: 1
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 评查点类型定义
|
* 评查点类型定义
|
||||||
* 用于展示单个评查结果
|
* 用于展示单个评查结果
|
||||||
@@ -1538,7 +1512,7 @@ export function ReviewPointsList({
|
|||||||
for (const item of chain) {
|
for (const item of chain) {
|
||||||
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
||||||
hasPage = true;
|
hasPage = true;
|
||||||
onReviewPointSelect(reviewPoint.id, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
|
onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions, item.data.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1552,7 +1526,7 @@ export function ReviewPointsList({
|
|||||||
// 遍历chain找到第一个有效的page
|
// 遍历chain找到第一个有效的page
|
||||||
for (const item of chain) {
|
for (const item of chain) {
|
||||||
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
|
onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions, item.data.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1592,11 +1566,11 @@ export function ReviewPointsList({
|
|||||||
// 假设onReviewPointSelect在作用域内可用
|
// 假设onReviewPointSelect在作用域内可用
|
||||||
const reviewPointId = reviewPoint.id as string;
|
const reviewPointId = reviewPoint.id as string;
|
||||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPointId, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
|
onReviewPointSelect(reviewPointId, Number(item.data.page), item.data.char_positions, item.data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){
|
else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]), resolveCharPositions(item.data), item.data.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]), item.data.char_positions, item.data.value);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
toastService.error(`没有找到${item.field}对应的索引内容`);
|
toastService.error(`没有找到${item.field}对应的索引内容`);
|
||||||
@@ -1675,11 +1649,11 @@ export function ReviewPointsList({
|
|||||||
if (chain[0].data.page) {
|
if (chain[0].data.page) {
|
||||||
const reviewPointId = reviewPoint.id as string;
|
const reviewPointId = reviewPoint.id as string;
|
||||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPointId, chain[0].data.page, resolveCharPositions(chain[0].data), chain[0].data.value);
|
onReviewPointSelect(reviewPointId, chain[0].data.page, chain[0].data.char_positions, chain[0].data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){
|
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]), resolveCharPositions(chain[0].data), chain[0].data.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]), chain[0].data.char_positions, chain[0].data.value);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
toastService.error(`没有找到${chain[0].field}对应的索引内容`);
|
toastService.error(`没有找到${chain[0].field}对应的索引内容`);
|
||||||
@@ -1701,11 +1675,11 @@ export function ReviewPointsList({
|
|||||||
if (chain[1].data.page) {
|
if (chain[1].data.page) {
|
||||||
const reviewPointId = reviewPoint.id as string;
|
const reviewPointId = reviewPoint.id as string;
|
||||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPointId, chain[1].data.page, resolveCharPositions(chain[1].data), chain[1].data.value);
|
onReviewPointSelect(reviewPointId, chain[1].data.page, chain[1].data.char_positions, chain[1].data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){
|
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]), resolveCharPositions(chain[1].data), chain[1].data.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]), chain[1].data.char_positions, chain[1].data.value);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
toastService.error(`没有找到${chain[1].field}对应的索引内容`);
|
toastService.error(`没有找到${chain[1].field}对应的索引内容`);
|
||||||
@@ -1841,9 +1815,9 @@ export function ReviewPointsList({
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1852,9 +1826,9 @@ export function ReviewPointsList({
|
|||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1922,7 +1896,6 @@ export function ReviewPointsList({
|
|||||||
fields?: Record<string, {
|
fields?: Record<string, {
|
||||||
page: number | string;
|
page: number | string;
|
||||||
value: string;
|
value: string;
|
||||||
res: boolean;
|
|
||||||
char_positions?: CharPosition[];
|
char_positions?: CharPosition[];
|
||||||
}>;
|
}>;
|
||||||
ai_suggestion?: {
|
ai_suggestion?: {
|
||||||
@@ -1981,14 +1954,14 @@ export function ReviewPointsList({
|
|||||||
<button
|
<button
|
||||||
key={`field-${index}`}
|
key={`field-${index}`}
|
||||||
className={`border border-gray w-full
|
className={`border border-gray w-full
|
||||||
rounded-md overflow-hidden mb-2 ${value.res ? 'bg-[rgba(246,255,237,1)]' : 'bg-[rgba(255,251,230,1)]'} flex
|
rounded-md overflow-hidden mb-2 ${res ? 'bg-[rgba(246,255,237,1)]' : 'bg-[rgba(255,251,230,1)]'} flex
|
||||||
hover:shadow-[0_0_10px_rgba(0,0,0,0.1)] ${value.res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'}`}
|
hover:shadow-[0_0_10px_rgba(0,0,0,0.1)] ${res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (value.page && typeof onReviewPointSelect === 'function') {
|
if (value.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(value.page), resolveCharPositions(value), value.value);
|
onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions, value.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), resolveCharPositions(value), value.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), value.char_positions, value.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${key}对应的索引内容`);
|
toastService.error(`没有找到${key}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1998,9 +1971,9 @@ export function ReviewPointsList({
|
|||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (value.page && typeof onReviewPointSelect === 'function') {
|
if (value.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(value.page), resolveCharPositions(value), value.value);
|
onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions, value.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), resolveCharPositions(value), value.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), value.char_positions, value.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${key}对应的索引内容`);
|
toastService.error(`没有找到${key}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -2031,7 +2004,7 @@ export function ReviewPointsList({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`w-8 flex items-center justify-center rounded-r-md group relative`}>
|
<div className={`w-8 flex items-center justify-center rounded-r-md group relative`}>
|
||||||
{value.res ? (
|
{res ? (
|
||||||
<i className="ri-check-line text-success text-base hover:text-green-800" ></i>
|
<i className="ri-check-line text-success text-base hover:text-green-800" ></i>
|
||||||
) : (
|
) : (
|
||||||
<i className="ri-alert-line text-warning text-base hover:text-yellow-800" ></i>
|
<i className="ri-alert-line text-warning text-base hover:text-yellow-800" ></i>
|
||||||
@@ -2048,7 +2021,7 @@ export function ReviewPointsList({
|
|||||||
<div className={`rounded-md flex flex-row items-center`}>
|
<div className={`rounded-md flex flex-row items-center`}>
|
||||||
<div className="text-xs text-gray-600 pl-1 whitespace-nowrap">大模型判断:</div>
|
<div className="text-xs text-gray-600 pl-1 whitespace-nowrap">大模型判断:</div>
|
||||||
<div className={`p-1 text-xs rounded-full min-w-[50px] text-center`}>
|
<div className={`p-1 text-xs rounded-full min-w-[50px] text-center`}>
|
||||||
{ value.res ? '通过' : '不通过'}
|
{res ? '通过' : '不通过'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2717,10 +2690,7 @@ export function ReviewPointsList({
|
|||||||
{/* <div className='flex flex-col'> */}
|
{/* <div className='flex flex-col'> */}
|
||||||
<div className="flex items-center gap-2 max-w-[75%]">
|
<div className="flex items-center gap-2 max-w-[75%]">
|
||||||
<div className="review-point-title text-left text-blue-500 break-all">{reviewPoint.pointName}</div>
|
<div className="review-point-title text-left text-blue-500 break-all">{reviewPoint.pointName}</div>
|
||||||
{ reviewPoint.pointName === '签署乙方详细信息校验' && (() => {
|
{ reviewPoint.pointName === '签署乙方详细信息校验' && (
|
||||||
const firstContentKey = reviewPoint.content ? Object.keys(reviewPoint.content)[0] : undefined;
|
|
||||||
const firstContentValue = firstContentKey ? reviewPoint.content![firstContentKey]?.value : undefined;
|
|
||||||
return (
|
|
||||||
<button
|
<button
|
||||||
className="enterprise-info-btn"
|
className="enterprise-info-btn"
|
||||||
style={{
|
style={{
|
||||||
@@ -2733,25 +2703,27 @@ export function ReviewPointsList({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
transition: 'all 0.2s',
|
transition: 'all 0.2s',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
cursor: firstContentValue ? 'pointer' : 'not-allowed',
|
cursor: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? 'pointer' : 'not-allowed',
|
||||||
backgroundColor: firstContentValue ? '#00684a' : '#e5e7eb',
|
backgroundColor: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? '#00684a' : '#e5e7eb',
|
||||||
color: firstContentValue ? '#ffffff' : '#9ca3af',
|
color: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? '#ffffff' : '#9ca3af',
|
||||||
}}
|
}}
|
||||||
disabled={!firstContentValue}
|
disabled={!reviewPoint.content?.['合同主体信息-乙方名称']?.value}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const companyName = typeof firstContentValue === 'string' ? firstContentValue : String(firstContentValue || '');
|
const companyNameValue = reviewPoint.content?.['合同主体信息-乙方名称']?.value;
|
||||||
|
// console.log('companyNameValue', companyNameValue);
|
||||||
|
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
|
||||||
if (companyName) {
|
if (companyName) {
|
||||||
handleCorporateInfoClick(companyName);
|
handleCorporateInfoClick(companyName);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-乙方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#005a3f';
|
e.currentTarget.style.backgroundColor = '#005a3f';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-乙方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#00684a';
|
e.currentTarget.style.backgroundColor = '#00684a';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -2759,12 +2731,8 @@ export function ReviewPointsList({
|
|||||||
<i className="ri-eye-line"></i>
|
<i className="ri-eye-line"></i>
|
||||||
乙方企业信息
|
乙方企业信息
|
||||||
</button>
|
</button>
|
||||||
);
|
)}
|
||||||
})()}
|
{ reviewPoint.pointName === '签署甲方详细信息校验' && (
|
||||||
{ reviewPoint.pointName === '签署甲方详细信息校验' && (() => {
|
|
||||||
const firstContentKey = reviewPoint.content ? Object.keys(reviewPoint.content)[0] : undefined;
|
|
||||||
const firstContentValue = firstContentKey ? reviewPoint.content![firstContentKey]?.value : undefined;
|
|
||||||
return (
|
|
||||||
<button
|
<button
|
||||||
className="enterprise-info-btn"
|
className="enterprise-info-btn"
|
||||||
style={{
|
style={{
|
||||||
@@ -2777,25 +2745,26 @@ export function ReviewPointsList({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
transition: 'all 0.2s',
|
transition: 'all 0.2s',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
cursor: firstContentValue ? 'pointer' : 'not-allowed',
|
cursor: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? 'pointer' : 'not-allowed',
|
||||||
backgroundColor: firstContentValue ? '#00684a' : '#e5e7eb',
|
backgroundColor: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? '#00684a' : '#e5e7eb',
|
||||||
color: firstContentValue ? '#ffffff' : '#9ca3af',
|
color: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? '#ffffff' : '#9ca3af',
|
||||||
}}
|
}}
|
||||||
disabled={!firstContentValue}
|
disabled={!reviewPoint.content?.['合同主体信息-甲方名称']?.value}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const companyName = typeof firstContentValue === 'string' ? firstContentValue : String(firstContentValue || '');
|
const companyNameValue = reviewPoint.content?.['合同主体信息-甲方名称']?.value;
|
||||||
|
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
|
||||||
if (companyName) {
|
if (companyName) {
|
||||||
handleCorporateInfoClick(companyName);
|
handleCorporateInfoClick(companyName);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-甲方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#005a3f';
|
e.currentTarget.style.backgroundColor = '#005a3f';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-甲方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#00684a';
|
e.currentTarget.style.backgroundColor = '#00684a';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -2803,8 +2772,7 @@ export function ReviewPointsList({
|
|||||||
<i className="ri-eye-line"></i>
|
<i className="ri-eye-line"></i>
|
||||||
甲方企业信息
|
甲方企业信息
|
||||||
</button>
|
</button>
|
||||||
);
|
)}
|
||||||
})()}
|
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="review-point-header flex justify-between items-start">
|
{/* <div className="review-point-header flex justify-between items-start">
|
||||||
<div className="flex-1 text-left min-w-[25%] font-medium text-[13px]">{reviewPoint.title}</div>
|
<div className="flex-1 text-left min-w-[25%] font-medium text-[13px]">{reviewPoint.title}</div>
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ interface FilePreviewProps {
|
|||||||
activeReviewPointResultId: string | null;
|
activeReviewPointResultId: string | null;
|
||||||
targetPage?: number; // 新增目标页码参数
|
targetPage?: number; // 新增目标页码参数
|
||||||
charPositions?: Array<{ box: number[][], char: string, score: number }>; // 字符位置信息(仅用于PDF)
|
charPositions?: Array<{ box: number[][], char: string, score: number }>; // 字符位置信息(仅用于PDF)
|
||||||
textBbox?: { x_min: number; y_min: number; x_max: number; y_max: number }; // GraphRAG段落级坐标
|
|
||||||
highlightValue?: string; // 高亮文本值(用于DOCX)
|
highlightValue?: string; // 高亮文本值(用于DOCX)
|
||||||
isStructuredView?: boolean; // 是否显示结构化视图
|
isStructuredView?: boolean; // 是否显示结构化视图
|
||||||
userInfo?: {
|
userInfo?: {
|
||||||
@@ -75,7 +74,7 @@ export interface FilePreviewHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// export function FilePreview({ fileContent, reviewPoints, activeReviewPointResultId, targetPage }: FilePreviewProps) {
|
// export function FilePreview({ fileContent, reviewPoints, activeReviewPointResultId, targetPage }: FilePreviewProps) {
|
||||||
export const FilePreview = forwardRef<FilePreviewHandle, FilePreviewProps>(function FilePreview({ fileContent, activeReviewPointResultId, targetPage, charPositions, textBbox, highlightValue, isStructuredView = false, userInfo, aiSuggestionReplace, isTemplate = false }, ref) {
|
export const FilePreview = forwardRef<FilePreviewHandle, FilePreviewProps>(function FilePreview({ fileContent, activeReviewPointResultId, targetPage, charPositions, highlightValue, isStructuredView = false, userInfo, aiSuggestionReplace, isTemplate = false }, ref) {
|
||||||
// 获取文件类型
|
// 获取文件类型
|
||||||
const real_path = fileContent.path || fileContent.template_contract_path || '';
|
const real_path = fileContent.path || fileContent.template_contract_path || '';
|
||||||
const fileExtension = real_path.split('.').pop()?.toLowerCase();
|
const fileExtension = real_path.split('.').pop()?.toLowerCase();
|
||||||
@@ -237,7 +236,6 @@ export const FilePreview = forwardRef<FilePreviewHandle, FilePreviewProps>(funct
|
|||||||
filePath={real_path}
|
filePath={real_path}
|
||||||
targetPage={targetPage}
|
targetPage={targetPage}
|
||||||
charPositions={charPositions}
|
charPositions={charPositions}
|
||||||
textBbox={textBbox}
|
|
||||||
isStructuredView={isStructuredView}
|
isStructuredView={isStructuredView}
|
||||||
activeReviewPointResultId={activeReviewPointResultId}
|
activeReviewPointResultId={activeReviewPointResultId}
|
||||||
pageOffset={pageOffset}
|
pageOffset={pageOffset}
|
||||||
|
|||||||
@@ -82,32 +82,6 @@ export interface CharPosition {
|
|||||||
score: number; // OCR识别置信度
|
score: number; // OCR识别置信度
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* text_bbox -> CharPosition[] 转换
|
|
||||||
* GraphRAG 抽取结果只有 text_bbox (段落级坐标), 没有 char_positions (字符级坐标)。
|
|
||||||
* 将 text_bbox 转为单个 CharPosition 矩形框, 让 PdfPreview 的高亮逻辑复用。
|
|
||||||
*/
|
|
||||||
function resolveCharPositions(data: any): CharPosition[] | undefined {
|
|
||||||
// 优先用 char_positions
|
|
||||||
if (data?.char_positions && data.char_positions.length > 0) {
|
|
||||||
return data.char_positions;
|
|
||||||
}
|
|
||||||
// fallback: text_bbox -> CharPosition[]
|
|
||||||
if (data?.text_bbox) {
|
|
||||||
const b = data.text_bbox;
|
|
||||||
if (b.x_min != null && b.y_min != null && b.x_max != null && b.y_max != null
|
|
||||||
&& (b.x_max - b.x_min) > 0 && (b.y_max - b.y_min) > 0) {
|
|
||||||
return [{
|
|
||||||
box: [[b.x_min, b.y_min], [b.x_max, b.y_min], [b.x_max, b.y_max], [b.x_min, b.y_max]],
|
|
||||||
char: '',
|
|
||||||
score: 1
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 评查点类型定义
|
* 评查点类型定义
|
||||||
* 用于展示单个评查结果
|
* 用于展示单个评查结果
|
||||||
@@ -1288,7 +1262,7 @@ export function ReviewPointsList({
|
|||||||
for (const item of chain) {
|
for (const item of chain) {
|
||||||
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
||||||
hasPage = true;
|
hasPage = true;
|
||||||
onReviewPointSelect(reviewPoint.id, Number(item.data.page), resolveCharPositions(item.data));
|
onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1302,7 +1276,7 @@ export function ReviewPointsList({
|
|||||||
// 遍历chain找到第一个有效的page
|
// 遍历chain找到第一个有效的page
|
||||||
for (const item of chain) {
|
for (const item of chain) {
|
||||||
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
if (item.data.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(item.data.page), resolveCharPositions(item.data));
|
onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1338,15 +1312,15 @@ export function ReviewPointsList({
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (item.data.page) {
|
if (item.data.page) {
|
||||||
console.log('点击了长链条评查点', resolveCharPositions(item.data), item.data);
|
console.log('点击了长链条评查点', item.data.char_positions, item.data);
|
||||||
// 假设onReviewPointSelect在作用域内可用
|
// 假设onReviewPointSelect在作用域内可用
|
||||||
const reviewPointId = reviewPoint.id as string;
|
const reviewPointId = reviewPoint.id as string;
|
||||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPointId, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
|
onReviewPointSelect(reviewPointId, Number(item.data.page), item.data.char_positions, item.data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){
|
else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]), resolveCharPositions(item.data), item.data.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]), item.data.char_positions, item.data.value);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
toastService.error(`没有找到${item.field}对应的索引内容`);
|
toastService.error(`没有找到${item.field}对应的索引内容`);
|
||||||
@@ -1422,16 +1396,16 @@ export function ReviewPointsList({
|
|||||||
${res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'} transition-colors flex flex-col`}
|
${res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'} transition-colors flex flex-col`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
console.log('点击了短链1左', resolveCharPositions(chain[0].data), chain[0].data)
|
console.log('点击了短链1左', chain[0].data.char_positions, chain[0].data)
|
||||||
if (chain[0].data.page) {
|
if (chain[0].data.page) {
|
||||||
// console.log('点击了短链1左', resolveCharPositions(chain[0].data), chain[0].data)
|
// console.log('点击了短链1左', chain[0].data.char_positions, chain[0].data)
|
||||||
const reviewPointId = reviewPoint.id as string;
|
const reviewPointId = reviewPoint.id as string;
|
||||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPointId, chain[0].data.page, resolveCharPositions(chain[0].data), chain[0].data.value);
|
onReviewPointSelect(reviewPointId, chain[0].data.page, chain[0].data.char_positions, chain[0].data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){
|
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]), resolveCharPositions(chain[0].data),chain[0].data.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]), chain[0].data.char_positions,chain[0].data.value);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
toastService.error(`没有找到${chain[0].field}对应的索引内容`);
|
toastService.error(`没有找到${chain[0].field}对应的索引内容`);
|
||||||
@@ -1451,14 +1425,14 @@ export function ReviewPointsList({
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (chain[1].data.page) {
|
if (chain[1].data.page) {
|
||||||
console.log('点击了短链2右', resolveCharPositions(chain[1].data), chain[1].data)
|
console.log('点击了短链2右', chain[1].data.char_positions, chain[1].data)
|
||||||
const reviewPointId = reviewPoint.id as string;
|
const reviewPointId = reviewPoint.id as string;
|
||||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPointId, chain[1].data.page, resolveCharPositions(chain[1].data), chain[1].data.value);
|
onReviewPointSelect(reviewPointId, chain[1].data.page, chain[1].data.char_positions, chain[1].data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){
|
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]), resolveCharPositions(chain[1].data), chain[1].data.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]), chain[1].data.char_positions, chain[1].data.value);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
toastService.error(`没有找到${chain[1].field}对应的索引内容`);
|
toastService.error(`没有找到${chain[1].field}对应的索引内容`);
|
||||||
@@ -1595,10 +1569,10 @@ export function ReviewPointsList({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
||||||
console.log("点击了其他评查点", mainTypeValue)
|
console.log("点击了其他评查点", mainTypeValue)
|
||||||
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
// onReviewPointSelect(reviewPoint.id, undefined, resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
// onReviewPointSelect(reviewPoint.id, undefined, mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1607,7 +1581,7 @@ export function ReviewPointsList({
|
|||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), resolveCharPositions(mainTypeValue), mainTypeValue.value);
|
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1675,7 +1649,6 @@ export function ReviewPointsList({
|
|||||||
fields?: Record<string, {
|
fields?: Record<string, {
|
||||||
page: number | string;
|
page: number | string;
|
||||||
value: string;
|
value: string;
|
||||||
res: boolean;
|
|
||||||
char_positions?: CharPosition[];
|
char_positions?: CharPosition[];
|
||||||
res?: boolean;
|
res?: boolean;
|
||||||
}>;
|
}>;
|
||||||
@@ -1736,15 +1709,15 @@ export function ReviewPointsList({
|
|||||||
<button
|
<button
|
||||||
key={`field-${index}`}
|
key={`field-${index}`}
|
||||||
className={`border border-gray w-full
|
className={`border border-gray w-full
|
||||||
rounded-md overflow-hidden mb-2 ${value.res ? 'bg-[rgba(246,255,237,1)]' : 'bg-[rgba(255,251,230,1)]'} flex
|
rounded-md overflow-hidden mb-2 ${res ? 'bg-[rgba(246,255,237,1)]' : 'bg-[rgba(255,251,230,1)]'} flex
|
||||||
hover:shadow-[0_0_10px_rgba(0,0,0,0.1)] ${value.res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'}`}
|
hover:shadow-[0_0_10px_rgba(0,0,0,0.1)] ${res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (value.page && typeof onReviewPointSelect === 'function') {
|
if (value.page && typeof onReviewPointSelect === 'function') {
|
||||||
console.log("点击了大模型的评查点", resolveCharPositions(value), value)
|
console.log("点击了大模型的评查点", value.char_positions, value)
|
||||||
onReviewPointSelect(reviewPoint.id, Number(value.page), resolveCharPositions(value), value.value);
|
onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions, value.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), resolveCharPositions(value),value.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), value.char_positions,value.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${key}对应的索引内容`);
|
toastService.error(`没有找到${key}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1754,9 +1727,9 @@ export function ReviewPointsList({
|
|||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (value.page && typeof onReviewPointSelect === 'function') {
|
if (value.page && typeof onReviewPointSelect === 'function') {
|
||||||
onReviewPointSelect(reviewPoint.id, Number(value.page), resolveCharPositions(value), value.value);
|
onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions, value.value);
|
||||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
||||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), resolveCharPositions(value),value.value);
|
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), value.char_positions,value.value);
|
||||||
}else{
|
}else{
|
||||||
toastService.error(`没有找到${key}对应的索引内容`);
|
toastService.error(`没有找到${key}对应的索引内容`);
|
||||||
}
|
}
|
||||||
@@ -1787,8 +1760,7 @@ export function ReviewPointsList({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`w-8 flex items-center justify-center rounded-r-md group relative`}>
|
<div className={`w-8 flex items-center justify-center rounded-r-md group relative`}>
|
||||||
{/* {res ? ( */}
|
{res ? (
|
||||||
{ value.res ? (
|
|
||||||
<i className="ri-check-line text-success text-base hover:text-green-800" ></i>
|
<i className="ri-check-line text-success text-base hover:text-green-800" ></i>
|
||||||
) : (
|
) : (
|
||||||
<i className="ri-alert-line text-warning text-base hover:text-yellow-800" ></i>
|
<i className="ri-alert-line text-warning text-base hover:text-yellow-800" ></i>
|
||||||
@@ -1805,7 +1777,7 @@ export function ReviewPointsList({
|
|||||||
<div className={`rounded-md flex flex-row items-center`}>
|
<div className={`rounded-md flex flex-row items-center`}>
|
||||||
<div className="text-xs text-gray-600 pl-1 whitespace-nowrap">大模型判断:</div>
|
<div className="text-xs text-gray-600 pl-1 whitespace-nowrap">大模型判断:</div>
|
||||||
<div className={`p-1 text-xs rounded-full min-w-[50px] text-center`}>
|
<div className={`p-1 text-xs rounded-full min-w-[50px] text-center`}>
|
||||||
{ value.res ? '通过' : '不通过'}
|
{res ? '通过' : '不通过'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1902,7 +1874,6 @@ export function ReviewPointsList({
|
|||||||
if (!isReplaceDisabled && onAiSuggestionReplace && config.fields) {
|
if (!isReplaceDisabled && onAiSuggestionReplace && config.fields) {
|
||||||
// 从 config.fields[key] 中获取对应的字段信息
|
// 从 config.fields[key] 中获取对应的字段信息
|
||||||
const fieldData = config.fields[key];
|
const fieldData = config.fields[key];
|
||||||
console.log("替换原始数据", config, key)
|
|
||||||
if (fieldData) {
|
if (fieldData) {
|
||||||
// 调用回调函数,传递搜索文本(原文)、替换文本(AI建议)和页码
|
// 调用回调函数,传递搜索文本(原文)、替换文本(AI建议)和页码
|
||||||
onAiSuggestionReplace(
|
onAiSuggestionReplace(
|
||||||
@@ -2604,10 +2575,7 @@ export function ReviewPointsList({
|
|||||||
{/* <div className='flex flex-col'> */}
|
{/* <div className='flex flex-col'> */}
|
||||||
<div className="flex items-center gap-2 max-w-[75%]">
|
<div className="flex items-center gap-2 max-w-[75%]">
|
||||||
<div className="review-point-title text-left text-blue-500 break-all">{reviewPoint.pointName}</div>
|
<div className="review-point-title text-left text-blue-500 break-all">{reviewPoint.pointName}</div>
|
||||||
{ reviewPoint.pointName === '签署乙方详细信息校验' && (() => {
|
{ reviewPoint.pointName === '签署乙方详细信息校验' && (
|
||||||
const firstContentKey = reviewPoint.content ? Object.keys(reviewPoint.content)[0] : undefined;
|
|
||||||
const firstContentValue = firstContentKey ? reviewPoint.content![firstContentKey]?.value : undefined;
|
|
||||||
return (
|
|
||||||
<button
|
<button
|
||||||
className="enterprise-info-btn"
|
className="enterprise-info-btn"
|
||||||
style={{
|
style={{
|
||||||
@@ -2620,25 +2588,27 @@ export function ReviewPointsList({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
transition: 'all 0.2s',
|
transition: 'all 0.2s',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
cursor: firstContentValue ? 'pointer' : 'not-allowed',
|
cursor: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? 'pointer' : 'not-allowed',
|
||||||
backgroundColor: firstContentValue ? '#00684a' : '#e5e7eb',
|
backgroundColor: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? '#00684a' : '#e5e7eb',
|
||||||
color: firstContentValue ? '#ffffff' : '#9ca3af',
|
color: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? '#ffffff' : '#9ca3af',
|
||||||
}}
|
}}
|
||||||
disabled={!firstContentValue}
|
disabled={!reviewPoint.content?.['合同主体信息-乙方名称']?.value}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const companyName = typeof firstContentValue === 'string' ? firstContentValue : String(firstContentValue || '');
|
const companyNameValue = reviewPoint.content?.['合同主体信息-乙方名称']?.value;
|
||||||
|
// console.log('companyNameValue', companyNameValue);
|
||||||
|
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
|
||||||
if (companyName) {
|
if (companyName) {
|
||||||
handleCorporateInfoClick(companyName);
|
handleCorporateInfoClick(companyName);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-乙方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#005a3f';
|
e.currentTarget.style.backgroundColor = '#005a3f';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-乙方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#00684a';
|
e.currentTarget.style.backgroundColor = '#00684a';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -2646,12 +2616,8 @@ export function ReviewPointsList({
|
|||||||
<i className="ri-eye-line"></i>
|
<i className="ri-eye-line"></i>
|
||||||
乙方企业信息
|
乙方企业信息
|
||||||
</button>
|
</button>
|
||||||
);
|
)}
|
||||||
})()}
|
{ reviewPoint.pointName === '签署甲方详细信息校验' && (
|
||||||
{ reviewPoint.pointName === '签署甲方详细信息校验' && (() => {
|
|
||||||
const firstContentKey = reviewPoint.content ? Object.keys(reviewPoint.content)[0] : undefined;
|
|
||||||
const firstContentValue = firstContentKey ? reviewPoint.content![firstContentKey]?.value : undefined;
|
|
||||||
return (
|
|
||||||
<button
|
<button
|
||||||
className="enterprise-info-btn"
|
className="enterprise-info-btn"
|
||||||
style={{
|
style={{
|
||||||
@@ -2664,25 +2630,26 @@ export function ReviewPointsList({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
transition: 'all 0.2s',
|
transition: 'all 0.2s',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
cursor: firstContentValue ? 'pointer' : 'not-allowed',
|
cursor: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? 'pointer' : 'not-allowed',
|
||||||
backgroundColor: firstContentValue ? '#00684a' : '#e5e7eb',
|
backgroundColor: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? '#00684a' : '#e5e7eb',
|
||||||
color: firstContentValue ? '#ffffff' : '#9ca3af',
|
color: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? '#ffffff' : '#9ca3af',
|
||||||
}}
|
}}
|
||||||
disabled={!firstContentValue}
|
disabled={!reviewPoint.content?.['合同主体信息-甲方名称']?.value}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const companyName = typeof firstContentValue === 'string' ? firstContentValue : String(firstContentValue || '');
|
const companyNameValue = reviewPoint.content?.['合同主体信息-甲方名称']?.value;
|
||||||
|
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
|
||||||
if (companyName) {
|
if (companyName) {
|
||||||
handleCorporateInfoClick(companyName);
|
handleCorporateInfoClick(companyName);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-甲方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#005a3f';
|
e.currentTarget.style.backgroundColor = '#005a3f';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
if (firstContentValue) {
|
if (reviewPoint.content?.['合同主体信息-甲方名称']?.value) {
|
||||||
e.currentTarget.style.backgroundColor = '#00684a';
|
e.currentTarget.style.backgroundColor = '#00684a';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -2690,8 +2657,7 @@ export function ReviewPointsList({
|
|||||||
<i className="ri-eye-line"></i>
|
<i className="ri-eye-line"></i>
|
||||||
甲方企业信息
|
甲方企业信息
|
||||||
</button>
|
</button>
|
||||||
);
|
)}
|
||||||
})()}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="review-point-header flex justify-between items-start">
|
{/* <div className="review-point-header flex justify-between items-start">
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ interface PdfPreviewProps {
|
|||||||
filePath: string; // PDF 文件路径
|
filePath: string; // PDF 文件路径
|
||||||
targetPage?: number; // 目标页码
|
targetPage?: number; // 目标页码
|
||||||
charPositions?: Array<{ box: number[][], char: string, score: number }>; // 字符位置信息(用于高亮显示)
|
charPositions?: Array<{ box: number[][], char: string, score: number }>; // 字符位置信息(用于高亮显示)
|
||||||
textBbox?: { x_min: number; y_min: number; x_max: number; y_max: number }; // GraphRAG段落级坐标
|
|
||||||
isStructuredView?: boolean; // 是否结构化视图
|
isStructuredView?: boolean; // 是否结构化视图
|
||||||
activeReviewPointResultId?: string | null; // 激活的评查点结果ID
|
activeReviewPointResultId?: string | null; // 激活的评查点结果ID
|
||||||
pageOffset?: number; // 页码偏移量(用于调整 OCR 结果的页码)
|
pageOffset?: number; // 页码偏移量(用于调整 OCR 结果的页码)
|
||||||
@@ -50,7 +49,6 @@ export function PdfPreview({
|
|||||||
filePath,
|
filePath,
|
||||||
targetPage,
|
targetPage,
|
||||||
charPositions,
|
charPositions,
|
||||||
textBbox,
|
|
||||||
isStructuredView = false,
|
isStructuredView = false,
|
||||||
activeReviewPointResultId,
|
activeReviewPointResultId,
|
||||||
pageOffset = 0,
|
pageOffset = 0,
|
||||||
@@ -229,18 +227,6 @@ export function PdfPreview({
|
|||||||
|
|
||||||
// ============ 处理字符位置数据,转换为高亮矩形 ============
|
// ============ 处理字符位置数据,转换为高亮矩形 ============
|
||||||
const processCharPositionsToHighlights = () => {
|
const processCharPositionsToHighlights = () => {
|
||||||
// GraphRAG fallback: charPositions 为空但有 textBbox 时,用段落级坐标画高亮
|
|
||||||
if ((!charPositions || charPositions.length === 0) && textBbox && targetPage) {
|
|
||||||
const scale = zoomLevel / 100;
|
|
||||||
return {
|
|
||||||
x: textBbox.x_min * coordinateScale * scale,
|
|
||||||
y: textBbox.y_min * coordinateScale * scale,
|
|
||||||
width: (textBbox.x_max - textBbox.x_min) * coordinateScale * scale,
|
|
||||||
height: (textBbox.y_max - textBbox.y_min) * coordinateScale * scale,
|
|
||||||
text: ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!charPositions || charPositions.length === 0 || !targetPage) {
|
if (!charPositions || charPositions.length === 0 || !targetPage) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -47,11 +47,11 @@ export const portConfigs: Record<string, Partial<ApiConfig>> = {
|
|||||||
// 梅州
|
// 梅州
|
||||||
'51703': {
|
'51703': {
|
||||||
|
|
||||||
// baseUrl: 'http://nas.7bm.co:8073',
|
baseUrl: 'http://nas.7bm.co:8073',
|
||||||
// documentUrl: 'http://nas.7bm.co:8073/docauditai/',
|
documentUrl: 'http://nas.7bm.co:8073/docauditai/',
|
||||||
// uploadUrl: 'http://nas.7bm.co:8073/api/v2/documents',
|
uploadUrl: 'http://nas.7bm.co:8073/api/v2/documents',
|
||||||
// collaboraUrl: 'http://nas.7bm.co:9980',
|
collaboraUrl: 'http://nas.7bm.co:9980',
|
||||||
// appUrl: 'http://nas.7bm.co:51703',
|
appUrl: 'http://nas.7bm.co:51703',
|
||||||
|
|
||||||
|
|
||||||
// baseUrl: 'http://172.16.0.56:8073',
|
// baseUrl: 'http://172.16.0.56:8073',
|
||||||
@@ -60,11 +60,11 @@ export const portConfigs: Record<string, Partial<ApiConfig>> = {
|
|||||||
// collaboraUrl: 'http://172.16.0.81:9980',
|
// collaboraUrl: 'http://172.16.0.81:9980',
|
||||||
// appUrl: 'http://172.16.0.34:51703',
|
// appUrl: 'http://172.16.0.34:51703',
|
||||||
|
|
||||||
baseUrl: 'http://nas.7bm.co:8073',
|
// baseUrl: 'http://10.79.97.17:8000',
|
||||||
documentUrl: 'http://nas.7bm.co:8073/docauditai/',
|
// documentUrl: 'http://10.79.97.17:8000/docauditai/',
|
||||||
uploadUrl: 'http://nas.7bm.co:8073/api/v2/documents',
|
// uploadUrl: 'http://10.79.97.17:8000/api/v2/documents',
|
||||||
collaboraUrl: 'http://nas.7bm.co:9980',
|
// collaboraUrl: 'http://10.79.97.17:9980',
|
||||||
appUrl: 'http://nas.7bm.co:51703',
|
// appUrl: 'http://10.79.97.17:51703',
|
||||||
|
|
||||||
oauth: {
|
oauth: {
|
||||||
redirectUri: 'http://10.79.97.17:51703/callback',
|
redirectUri: 'http://10.79.97.17:51703/callback',
|
||||||
|
|||||||
@@ -100,23 +100,6 @@ const AREA_OPTIONS = [
|
|||||||
{ value: "云浮", label: "云浮" },
|
{ value: "云浮", label: "云浮" },
|
||||||
{ value: "揭阳", label: "揭阳" },
|
{ value: "揭阳", label: "揭阳" },
|
||||||
{ value: "潮州", label: "潮州" },
|
{ value: "潮州", label: "潮州" },
|
||||||
{ value: "湛江", label: "湛江" },
|
|
||||||
// { value: "广州", label: "广州" },
|
|
||||||
// { value: "深圳", label: "深圳" },
|
|
||||||
// { value: "珠海", label: "珠海" },
|
|
||||||
// { value: "佛山", label: "佛山" },
|
|
||||||
// { value: "惠州", label: "惠州" },
|
|
||||||
// { value: "江门", label: "江门" },
|
|
||||||
// { value: "茂名", label: "茂名" },
|
|
||||||
// { value: "汕尾", label: "汕尾" },
|
|
||||||
// { value: "汕头", label: "汕头" },
|
|
||||||
// { value: "河源", label: "河源" },
|
|
||||||
// { value: "阳江", label: "阳江" },
|
|
||||||
// { value: "清远", label: "清远" },
|
|
||||||
// { value: "东莞", label: "东莞" },
|
|
||||||
// { value: "中山", label: "中山" },
|
|
||||||
// { value: "肇庆", label: "肇庆" },
|
|
||||||
// { value: "韶关", label: "韶关" },
|
|
||||||
{ value: "省局", label: "省局" }
|
{ value: "省局", label: "省局" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -76,23 +76,6 @@ const AREA_OPTIONS = [
|
|||||||
{ value: "云浮", label: "云浮" },
|
{ value: "云浮", label: "云浮" },
|
||||||
{ value: "揭阳", label: "揭阳" },
|
{ value: "揭阳", label: "揭阳" },
|
||||||
{ value: "潮州", label: "潮州" },
|
{ value: "潮州", label: "潮州" },
|
||||||
{ value: "湛江", label: "湛江" },
|
|
||||||
// { value: "广州", label: "广州" },
|
|
||||||
// { value: "深圳", label: "深圳" },
|
|
||||||
// { value: "珠海", label: "珠海" },
|
|
||||||
// { value: "佛山", label: "佛山" },
|
|
||||||
// { value: "惠州", label: "惠州" },
|
|
||||||
// { value: "江门", label: "江门" },
|
|
||||||
// { value: "茂名", label: "茂名" },
|
|
||||||
// { value: "汕尾", label: "汕尾" },
|
|
||||||
// { value: "汕头", label: "汕头" },
|
|
||||||
// { value: "河源", label: "河源" },
|
|
||||||
// { value: "阳江", label: "阳江" },
|
|
||||||
// { value: "清远", label: "清远" },
|
|
||||||
// { value: "东莞", label: "东莞" },
|
|
||||||
// { value: "中山", label: "中山" },
|
|
||||||
// { value: "肇庆", label: "肇庆" },
|
|
||||||
// { value: "韶关", label: "韶关" },
|
|
||||||
{ value: "省局", label: "省局" }
|
{ value: "省局", label: "省局" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -386,7 +386,6 @@ export default function ReviewDetails() {
|
|||||||
const [targetPage, setTargetPage] = useState<number | undefined>(undefined);
|
const [targetPage, setTargetPage] = useState<number | undefined>(undefined);
|
||||||
const [templateTargetPage, setTemplateTargetPage] = useState<number | undefined>(undefined);
|
const [templateTargetPage, setTemplateTargetPage] = useState<number | undefined>(undefined);
|
||||||
const [charPositions, setCharPositions] = useState<Array<{ box: number[][], char: string, score: number }> | undefined>(undefined);
|
const [charPositions, setCharPositions] = useState<Array<{ box: number[][], char: string, score: number }> | undefined>(undefined);
|
||||||
const [textBbox, setTextBbox] = useState<{ x_min: number; y_min: number; x_max: number; y_max: number } | undefined>(undefined);
|
|
||||||
const [highlightValue, setHighlightValue] = useState<string | undefined>(undefined);
|
const [highlightValue, setHighlightValue] = useState<string | undefined>(undefined);
|
||||||
const [pendingUpdate, setPendingUpdate] = useState<{
|
const [pendingUpdate, setPendingUpdate] = useState<{
|
||||||
reviewPointResultId: string;
|
reviewPointResultId: string;
|
||||||
@@ -552,19 +551,17 @@ export default function ReviewDetails() {
|
|||||||
setActiveTab(tabKey);
|
setActiveTab(tabKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReviewPointSelect = (reviewPointId: string, page?: number, charPos?: Array<{ box: number[][], char: string, score: number }>, value?: string, bbox?: { x_min: number; y_min: number; x_max: number; y_max: number }) => {
|
const handleReviewPointSelect = (reviewPointId: string, page?: number, charPos?: Array<{ box: number[][], char: string, score: number }>, value?: string) => {
|
||||||
// 如果点击的是相同的评查点,但有page参数,先重置targetPage以确保useEffect能够触发
|
// 如果点击的是相同的评查点,但有page参数,先重置targetPage以确保useEffect能够触发
|
||||||
if (reviewPointId === activeReviewPointResultId && page) {
|
if (reviewPointId === activeReviewPointResultId && page) {
|
||||||
setTargetPage(undefined);
|
setTargetPage(undefined);
|
||||||
setCharPositions(undefined);
|
setCharPositions(undefined);
|
||||||
setTextBbox(undefined);
|
|
||||||
setHighlightValue(undefined);
|
setHighlightValue(undefined);
|
||||||
// 使用setTimeout确保状态更新后再设置新的targetPage、charPositions和highlightValue
|
// 使用setTimeout确保状态更新后再设置新的targetPage、charPositions和highlightValue
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setActiveReviewPointResultId(reviewPointId);
|
setActiveReviewPointResultId(reviewPointId);
|
||||||
setTargetPage(page);
|
setTargetPage(page);
|
||||||
setCharPositions(charPos);
|
setCharPositions(charPos);
|
||||||
setTextBbox(bbox);
|
|
||||||
setHighlightValue(value);
|
setHighlightValue(value);
|
||||||
}, 0);
|
}, 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -572,7 +569,6 @@ export default function ReviewDetails() {
|
|||||||
setActiveReviewPointResultId(reviewPointId);
|
setActiveReviewPointResultId(reviewPointId);
|
||||||
setTargetPage(page);
|
setTargetPage(page);
|
||||||
setCharPositions(charPos);
|
setCharPositions(charPos);
|
||||||
setTextBbox(bbox);
|
|
||||||
setHighlightValue(value);
|
setHighlightValue(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -970,7 +966,6 @@ export default function ReviewDetails() {
|
|||||||
activeReviewPointResultId={activeReviewPointResultId}
|
activeReviewPointResultId={activeReviewPointResultId}
|
||||||
targetPage={targetPage}
|
targetPage={targetPage}
|
||||||
charPositions={charPositions}
|
charPositions={charPositions}
|
||||||
textBbox={textBbox}
|
|
||||||
highlightValue={highlightValue}
|
highlightValue={highlightValue}
|
||||||
userInfo={loaderData.userInfo}
|
userInfo={loaderData.userInfo}
|
||||||
aiSuggestionReplace={aiSuggestionReplace}
|
aiSuggestionReplace={aiSuggestionReplace}
|
||||||
@@ -1024,7 +1019,6 @@ export default function ReviewDetails() {
|
|||||||
activeReviewPointResultId={activeReviewPointResultId}
|
activeReviewPointResultId={activeReviewPointResultId}
|
||||||
targetPage={targetPage}
|
targetPage={targetPage}
|
||||||
charPositions={charPositions}
|
charPositions={charPositions}
|
||||||
textBbox={textBbox}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user