feat: 1. 添加企查查的按钮。新增相关组件和对接接口进行显示。
2. 为51707端口添加只存在交叉评查入口的项目启动配置。入口页添加相关的区分。 3. 完善文档列表的权限功能控制。 4. 隐藏系统概览中高风险用户的统计模块。 fix: 1. 修复合同起草无权访问却生成了新的模板文件的问题。 2. 修复文档类型无法编辑入口模块的问题。
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* 企业工商信息展示组件
|
||||
*/
|
||||
|
||||
import type { BusinessInfoProps } from './types';
|
||||
import { EntTypeLabel } from './types';
|
||||
|
||||
/** 格式化日期(移除时间部分) */
|
||||
function formatDate(dateStr: string | null | undefined): string {
|
||||
if (!dateStr) return '-';
|
||||
// 移除时间部分,只保留日期
|
||||
return dateStr.split(' ')[0] || dateStr;
|
||||
}
|
||||
|
||||
/** 格式化金额 */
|
||||
function formatAmount(amount: string | null | undefined, unit?: string, ccy?: string): string {
|
||||
if (!amount) return '-';
|
||||
const currencyMap: Record<string, string> = {
|
||||
'CNY': '人民币',
|
||||
'USD': '美元',
|
||||
'HKD': '港币',
|
||||
'EUR': '欧元',
|
||||
};
|
||||
const currencyLabel = ccy ? currencyMap[ccy] || ccy : '';
|
||||
return `${amount}${unit || ''}${currencyLabel ? ` (${currencyLabel})` : ''}`;
|
||||
}
|
||||
|
||||
export function BusinessInfo({ data, loading, error }: BusinessInfoProps) {
|
||||
// 加载中状态
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm p-6">
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<i className="ri-loader-4-line animate-spin text-2xl text-gray-400 mr-2"></i>
|
||||
<span className="text-gray-500">加载企业信息中...</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 错误状态
|
||||
if (error) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm p-6">
|
||||
<div className="flex items-center justify-center py-12 text-red-500">
|
||||
<i className="ri-error-warning-line text-2xl mr-2"></i>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 无数据状态
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm p-6">
|
||||
<div className="flex items-center justify-center py-12 text-gray-400">
|
||||
<i className="ri-building-line text-2xl mr-2"></i>
|
||||
<span>暂无企业工商信息</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 判断是否有注销/吊销信息
|
||||
const hasRevokeInfo = data.RevokeInfo && (data.RevokeInfo.CancelDate || data.RevokeInfo.RevokeDate);
|
||||
|
||||
// 获取状态标签颜色
|
||||
const getStatusColor = (status: string) => {
|
||||
if (status === '存续' || status === '在业' || status === '开业') {
|
||||
return 'bg-green-100 text-green-700 border-green-200';
|
||||
}
|
||||
if (status === '注销' || status === '吊销') {
|
||||
return 'bg-red-100 text-red-700 border-red-200';
|
||||
}
|
||||
return 'bg-gray-100 text-gray-700 border-gray-200';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm">
|
||||
{/* 标题栏 */}
|
||||
<div className="px-6 py-4 border-b border-gray-100">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<i className="ri-building-2-line text-xl text-[#00684a] mr-2"></i>
|
||||
<h3 className="text-lg font-medium text-gray-900">企业工商信息</h3>
|
||||
</div>
|
||||
{data.Status && (
|
||||
<span className={`px-3 py-1 text-sm rounded-full border ${getStatusColor(data.Status)}`}>
|
||||
{data.Status}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 企业头部信息 */}
|
||||
<div className="px-6 py-4 bg-gray-50 border-b border-gray-100">
|
||||
<div className="flex items-start gap-4">
|
||||
{data.ImageUrl && (
|
||||
<img
|
||||
src={data.ImageUrl}
|
||||
alt="企业Logo"
|
||||
className="w-16 h-16 rounded-lg object-contain bg-white border border-gray-200"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h2 className="text-xl font-semibold text-gray-900 truncate">{data.Name}</h2>
|
||||
<div className="mt-1 flex flex-wrap items-center gap-2 text-sm text-gray-500">
|
||||
{data.CreditCode && (
|
||||
<span className="bg-white px-2 py-0.5 rounded border border-gray-200">
|
||||
统一社会信用代码:{data.CreditCode}
|
||||
</span>
|
||||
)}
|
||||
{data.EntType && (
|
||||
<span className="bg-[#e6f4ff] text-[#0958d9] px-2 py-0.5 rounded border border-[#91caff]">
|
||||
{EntTypeLabel[data.EntType] || '其他'}
|
||||
</span>
|
||||
)}
|
||||
{data.IsOnStock === '1' && (
|
||||
<span className="bg-orange-100 text-orange-700 px-2 py-0.5 rounded border border-orange-200">
|
||||
{data.StockType}:{data.StockNumber}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{/* 曾用名 */}
|
||||
{data.OriginalName && data.OriginalName.length > 0 && (
|
||||
<div className="mt-2 text-sm text-gray-500">
|
||||
<span className="text-gray-400">曾用名:</span>
|
||||
{data.OriginalName.map((item, index) => (
|
||||
<span key={index} className="mr-2">
|
||||
{item.Name}
|
||||
{item.ChangeDate && <span className="text-gray-400 text-xs ml-1">({formatDate(item.ChangeDate)})</span>}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 详细信息 */}
|
||||
<div className="px-6 py-4">
|
||||
{/* 基本信息 */}
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-medium text-gray-700 mb-3 flex items-center">
|
||||
<i className="ri-information-line mr-1 text-gray-400"></i>
|
||||
基本信息
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<InfoItem label="法定代表人" value={data.OperName} />
|
||||
<InfoItem label="企业类型" value={data.EconKind} />
|
||||
<InfoItem label="成立日期" value={formatDate(data.StartDate)} />
|
||||
<InfoItem label="核准日期" value={formatDate(data.CheckDate)} />
|
||||
<InfoItem label="营业期限" value={`${formatDate(data.TermStart)} 至 ${formatDate(data.TermEnd)}`} />
|
||||
<InfoItem label="登记机关" value={data.BelongOrg} />
|
||||
<InfoItem label="工商注册号" value={data.No} />
|
||||
<InfoItem label="组织机构代码" value={data.OrgNo} />
|
||||
{data.Area && (
|
||||
<InfoItem
|
||||
label="所属地区"
|
||||
value={`${data.Area.Province || ''}${data.Area.City || ''}${data.Area.County || ''}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 资本信息 */}
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-medium text-gray-700 mb-3 flex items-center">
|
||||
<i className="ri-money-cny-circle-line mr-1 text-gray-400"></i>
|
||||
资本信息
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<InfoItem
|
||||
label="注册资本"
|
||||
value={data.RegistCapi || formatAmount(data.RegisteredCapital, data.RegisteredCapitalUnit, data.RegisteredCapitalCCY)}
|
||||
/>
|
||||
<InfoItem
|
||||
label="实缴资本"
|
||||
value={data.RecCap || formatAmount(data.PaidUpCapital, data.PaidUpCapitalUnit, data.PaidUpCapitalCCY)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 注册地址 */}
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-medium text-gray-700 mb-3 flex items-center">
|
||||
<i className="ri-map-pin-line mr-1 text-gray-400"></i>
|
||||
注册地址
|
||||
</h4>
|
||||
<p className="text-sm text-gray-600 bg-gray-50 p-3 rounded-lg">{data.Address || '-'}</p>
|
||||
</div>
|
||||
|
||||
{/* 经营范围 */}
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-medium text-gray-700 mb-3 flex items-center">
|
||||
<i className="ri-file-list-3-line mr-1 text-gray-400"></i>
|
||||
经营范围
|
||||
</h4>
|
||||
<p className="text-sm text-gray-600 bg-gray-50 p-3 rounded-lg leading-relaxed">
|
||||
{data.Scope || '-'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 委派代表 */}
|
||||
{data.DesignatedRepresentativeList && data.DesignatedRepresentativeList.length > 0 && (
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-medium text-gray-700 mb-3 flex items-center">
|
||||
<i className="ri-user-star-line mr-1 text-gray-400"></i>
|
||||
委派代表
|
||||
</h4>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="bg-gray-50">
|
||||
<th className="px-4 py-2 text-left font-medium text-gray-600">合伙人名称</th>
|
||||
<th className="px-4 py-2 text-left font-medium text-gray-600">委派代表</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.DesignatedRepresentativeList.map((rep, index) => (
|
||||
<tr key={index} className="border-b border-gray-100">
|
||||
<td className="px-4 py-2 text-gray-700">{rep.PartnerName || '-'}</td>
|
||||
<td className="px-4 py-2 text-gray-700">{rep.DelegatedName || '-'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 注销/吊销信息 */}
|
||||
{hasRevokeInfo && (
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-medium text-red-600 mb-3 flex items-center">
|
||||
<i className="ri-error-warning-line mr-1"></i>
|
||||
注销/吊销信息
|
||||
</h4>
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{data.RevokeInfo?.CancelDate && (
|
||||
<>
|
||||
<InfoItem label="注销日期" value={formatDate(data.RevokeInfo.CancelDate)} labelClassName="text-red-600" />
|
||||
<InfoItem label="注销原因" value={data.RevokeInfo.CancelReason} labelClassName="text-red-600" />
|
||||
</>
|
||||
)}
|
||||
{data.RevokeInfo?.RevokeDate && (
|
||||
<>
|
||||
<InfoItem label="吊销日期" value={formatDate(data.RevokeInfo.RevokeDate)} labelClassName="text-red-600" />
|
||||
<InfoItem label="吊销原因" value={data.RevokeInfo.RevokeReason} labelClassName="text-red-600" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 更新时间 */}
|
||||
{data.UpdatedDate && (
|
||||
<div className="text-xs text-gray-400 text-right">
|
||||
数据更新时间:{formatDate(data.UpdatedDate)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 信息项组件 */
|
||||
interface InfoItemProps {
|
||||
label: string;
|
||||
value: string | null | undefined;
|
||||
labelClassName?: string;
|
||||
}
|
||||
|
||||
function InfoItem({ label, value, labelClassName = 'text-gray-500' }: InfoItemProps) {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<span className={`text-xs ${labelClassName}`}>{label}</span>
|
||||
<span className="text-sm text-gray-800 mt-0.5">{value || '-'}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
/**
|
||||
* 企业信息模态框组件
|
||||
* 用于展示企业工商信息和失信核查信息
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { CorporateInformation } from './CorporateInformation';
|
||||
import { toastService } from '../ui/Toast';
|
||||
import { messageService } from '../ui/MessageModal';
|
||||
import type { BusinessInfoResult, DishonestyResult, Paging } from './types';
|
||||
|
||||
export interface CorporateInfoModalProps {
|
||||
/** 是否显示模态框 */
|
||||
visible: boolean;
|
||||
/** 关闭模态框回调 */
|
||||
onClose: () => void;
|
||||
/** 企业名称(用于标题显示) */
|
||||
companyName?: string;
|
||||
/** 企业工商信息 */
|
||||
businessInfo: BusinessInfoResult | null;
|
||||
/** 失信核查数据 */
|
||||
dishonestyInfo: DishonestyResult | null;
|
||||
/** 失信核查分页信息 */
|
||||
dishonestyPaging?: Paging | null;
|
||||
/** 企业工商信息加载中 */
|
||||
businessLoading?: boolean;
|
||||
/** 失信核查加载中 */
|
||||
dishonestyLoading?: boolean;
|
||||
/** 企业工商信息错误 */
|
||||
businessError?: string | null;
|
||||
/** 失信核查错误 */
|
||||
dishonestyError?: string | null;
|
||||
/** 数据更新时间(ISO格式) */
|
||||
updatedAt?: string | null;
|
||||
/** 强制刷新回调(对接企查查重新查询) */
|
||||
onForceRefresh?: () => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化更新时间(UTC转北京时间)
|
||||
* @param isoString ISO格式的时间字符串
|
||||
* @returns 格式化后的北京时间字符串
|
||||
*/
|
||||
function formatUpdatedTime(isoString: string | null | undefined): string {
|
||||
if (!isoString) return '-';
|
||||
|
||||
try {
|
||||
const date = new Date(isoString);
|
||||
|
||||
// 检查日期是否有效
|
||||
if (isNaN(date.getTime())) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
// 使用 Intl.DateTimeFormat 格式化为北京时间
|
||||
const formatter = new Intl.DateTimeFormat('zh-CN', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false,
|
||||
});
|
||||
|
||||
return formatter.format(date);
|
||||
} catch {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
export function CorporateInfoModal({
|
||||
visible,
|
||||
onClose,
|
||||
companyName,
|
||||
businessInfo,
|
||||
dishonestyInfo,
|
||||
dishonestyPaging,
|
||||
businessLoading = false,
|
||||
dishonestyLoading = false,
|
||||
businessError,
|
||||
dishonestyError,
|
||||
updatedAt,
|
||||
onForceRefresh,
|
||||
}: CorporateInfoModalProps) {
|
||||
// 强制刷新按钮加载状态
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
// ESC 键关闭模态框
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape' && visible) {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[visible, onClose]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [handleKeyDown]);
|
||||
|
||||
// 阻止背景滚动
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
} else {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
return () => {
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
}, [visible]);
|
||||
|
||||
// 处理强制刷新按钮点击
|
||||
const handleForceRefreshClick = () => {
|
||||
messageService.show({
|
||||
title: '确认重新查询',
|
||||
message: '该操作将对接企查查API进行实时查询,会产生费用(约0.50元/次)。确定要继续吗?',
|
||||
type: 'warning',
|
||||
confirmText: '确认查询',
|
||||
cancelText: '取消',
|
||||
onConfirm: async () => {
|
||||
if (onForceRefresh) {
|
||||
setRefreshing(true);
|
||||
try {
|
||||
await onForceRefresh();
|
||||
toastService.success('已提交查询,请稍后再查看企业信息');
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('强制刷新失败:', error);
|
||||
toastService.error('查询失败,请稍后重试');
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="corporate-info-modal-overlay"
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
zIndex: 1000,
|
||||
}}
|
||||
onClick={(e) => {
|
||||
// 点击背景关闭
|
||||
if (e.target === e.currentTarget) {
|
||||
onClose();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="corporate-info-modal"
|
||||
style={{
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: '8px',
|
||||
width: '90%',
|
||||
maxWidth: '900px',
|
||||
maxHeight: '85vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* 模态框头部 */}
|
||||
<div
|
||||
className="corporate-info-modal-header"
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '16px 24px',
|
||||
borderBottom: '1px solid #e5e7eb',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||
<i
|
||||
className="ri-building-line"
|
||||
style={{ fontSize: '20px', color: '#00684a' }}
|
||||
></i>
|
||||
<h3
|
||||
style={{
|
||||
margin: 0,
|
||||
fontSize: '18px',
|
||||
fontWeight: 600,
|
||||
color: '#1f2937',
|
||||
}}
|
||||
>
|
||||
企业信息查询
|
||||
</h3>
|
||||
{companyName && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: '8px',
|
||||
padding: '2px 8px',
|
||||
backgroundColor: '#f3f4f6',
|
||||
borderRadius: '4px',
|
||||
fontSize: '14px',
|
||||
color: '#6b7280',
|
||||
}}
|
||||
>
|
||||
{companyName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: '4px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '4px',
|
||||
transition: 'background-color 0.2s',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = '#f3f4f6';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = 'transparent';
|
||||
}}
|
||||
title="关闭 (ESC)"
|
||||
>
|
||||
<i
|
||||
className="ri-close-line"
|
||||
style={{ fontSize: '24px', color: '#6b7280' }}
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 模态框内容 */}
|
||||
<div
|
||||
className="corporate-info-modal-body"
|
||||
style={{
|
||||
padding: '24px',
|
||||
overflowY: 'auto',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<CorporateInformation
|
||||
businessInfo={businessInfo}
|
||||
dishonestyInfo={dishonestyInfo}
|
||||
dishonestyPaging={dishonestyPaging}
|
||||
businessLoading={businessLoading}
|
||||
dishonestyLoading={dishonestyLoading}
|
||||
businessError={businessError}
|
||||
dishonestyError={dishonestyError}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 模态框底部 */}
|
||||
<div
|
||||
className="corporate-info-modal-footer"
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '12px 24px',
|
||||
borderTop: '1px solid #e5e7eb',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{/* 左侧:最近查询时间 */}
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
fontSize: '13px',
|
||||
color: '#6b7280',
|
||||
}}
|
||||
>
|
||||
<i className="ri-time-line" style={{ fontSize: '14px' }}></i>
|
||||
<span>最近查询时间:{formatUpdatedTime(updatedAt)}</span>
|
||||
</div>
|
||||
|
||||
{/* 右侧:按钮组 */}
|
||||
<div style={{ display: 'flex', gap: '12px' }}>
|
||||
{/* 对接企查查重新查询按钮 */}
|
||||
<button
|
||||
onClick={handleForceRefreshClick}
|
||||
disabled={refreshing || businessLoading || dishonestyLoading}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
backgroundColor: refreshing ? '#d1d5db' : '#00684a',
|
||||
border: 'none',
|
||||
borderRadius: '6px',
|
||||
fontSize: '14px',
|
||||
color: '#ffffff',
|
||||
cursor: refreshing || businessLoading || dishonestyLoading ? 'not-allowed' : 'pointer',
|
||||
transition: 'all 0.2s',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
opacity: refreshing || businessLoading || dishonestyLoading ? 0.6 : 1,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (!refreshing && !businessLoading && !dishonestyLoading) {
|
||||
e.currentTarget.style.backgroundColor = '#005a3f';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (!refreshing && !businessLoading && !dishonestyLoading) {
|
||||
e.currentTarget.style.backgroundColor = '#00684a';
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i className={refreshing ? 'ri-loader-4-line' : 'ri-refresh-line'} style={{ fontSize: '14px' }}></i>
|
||||
{refreshing ? '查询中...' : '对接企查查重新查询'}
|
||||
</button>
|
||||
|
||||
{/* 关闭按钮 */}
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
padding: '8px 24px',
|
||||
backgroundColor: '#f3f4f6',
|
||||
border: '1px solid #d1d5db',
|
||||
borderRadius: '6px',
|
||||
fontSize: '14px',
|
||||
color: '#374151',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = '#e5e7eb';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = '#f3f4f6';
|
||||
}}
|
||||
>
|
||||
关闭
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 企业综合信息展示组件
|
||||
* 整合企业工商信息和失信核查信息
|
||||
*/
|
||||
|
||||
import { BusinessInfo } from './BusinessInfo';
|
||||
import { DishonestyInfo } from './DishonestyInfo';
|
||||
import type { CorporateInformationProps } from './types';
|
||||
|
||||
export function CorporateInformation({
|
||||
businessInfo,
|
||||
dishonestyInfo,
|
||||
dishonestyPaging,
|
||||
businessLoading,
|
||||
dishonestyLoading,
|
||||
businessError,
|
||||
dishonestyError,
|
||||
}: CorporateInformationProps) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* 企业工商信息 */}
|
||||
<BusinessInfo
|
||||
data={businessInfo}
|
||||
loading={businessLoading}
|
||||
error={businessError}
|
||||
/>
|
||||
|
||||
{/* 失信核查信息 */}
|
||||
<DishonestyInfo
|
||||
data={dishonestyInfo}
|
||||
paging={dishonestyPaging}
|
||||
loading={dishonestyLoading}
|
||||
error={dishonestyError}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* 失信核查信息展示组件
|
||||
*/
|
||||
|
||||
import type { DishonestyInfoProps, DishonestyRecord } from './types';
|
||||
|
||||
/** 格式化日期 */
|
||||
function formatDate(dateStr: string | null | undefined): string {
|
||||
if (!dateStr) return '-';
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
/** 格式化金额(元转万元) */
|
||||
function formatAmount(amountStr: string | null | undefined): string {
|
||||
if (!amountStr) return '-';
|
||||
const amount = parseFloat(amountStr);
|
||||
if (isNaN(amount)) return amountStr;
|
||||
if (amount >= 10000) {
|
||||
return `${(amount / 10000).toFixed(2)}万元`;
|
||||
}
|
||||
return `${amount.toFixed(2)}元`;
|
||||
}
|
||||
|
||||
/** 获取履行情况标签颜色 */
|
||||
function getExecuteStatusColor(status: string): string {
|
||||
if (status === '全部履行') {
|
||||
return 'bg-green-100 text-green-700 border-green-200';
|
||||
}
|
||||
if (status === '部分履行') {
|
||||
return 'bg-yellow-100 text-yellow-700 border-yellow-200';
|
||||
}
|
||||
if (status === '全部未履行') {
|
||||
return 'bg-red-100 text-red-700 border-red-200';
|
||||
}
|
||||
return 'bg-gray-100 text-gray-700 border-gray-200';
|
||||
}
|
||||
|
||||
export function DishonestyInfo({ data, paging, loading, error }: DishonestyInfoProps) {
|
||||
// 加载中状态
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm p-6">
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<i className="ri-loader-4-line animate-spin text-2xl text-gray-400 mr-2"></i>
|
||||
<span className="text-gray-500">加载失信信息中...</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 错误状态
|
||||
if (error) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm p-6">
|
||||
<div className="flex items-center justify-center py-12 text-red-500">
|
||||
<i className="ri-error-warning-line text-2xl mr-2"></i>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 无失信记录状态
|
||||
if (!data || data.VerifyResult === 0 || !data.Data || data.Data.length === 0) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm">
|
||||
<div className="px-6 py-4 border-b border-gray-100">
|
||||
<div className="flex items-center">
|
||||
<i className="ri-shield-check-line text-xl text-[#00684a] mr-2"></i>
|
||||
<h3 className="text-lg font-medium text-gray-900">失信核查</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<div className="text-center">
|
||||
<div className="w-16 h-16 mx-auto mb-4 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<i className="ri-shield-check-fill text-3xl text-green-500"></i>
|
||||
</div>
|
||||
<p className="text-green-600 font-medium">暂无失信记录</p>
|
||||
<p className="text-sm text-gray-400 mt-1">该企业/个人未被列入失信被执行人名单</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm">
|
||||
{/* 标题栏 */}
|
||||
<div className="px-6 py-4 border-b border-gray-100">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<i className="ri-error-warning-fill text-xl text-red-500 mr-2"></i>
|
||||
<h3 className="text-lg font-medium text-gray-900">失信核查</h3>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="bg-red-100 text-red-700 px-3 py-1 text-sm rounded-full border border-red-200">
|
||||
存在失信记录
|
||||
</span>
|
||||
{paging && paging.TotalRecords > 0 && (
|
||||
<span className="text-sm text-gray-500">
|
||||
共 <span className="font-medium text-red-600">{paging.TotalRecords}</span> 条记录
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 失信记录列表 */}
|
||||
<div className="px-6 py-4">
|
||||
<div className="space-y-4">
|
||||
{data.Data.map((record, index) => (
|
||||
<DishonestyRecordCard key={record.Id || index} record={record} index={index + 1} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 分页提示 */}
|
||||
{paging && paging.TotalRecords > paging.PageSize && (
|
||||
<div className="mt-4 text-center text-sm text-gray-500">
|
||||
当前显示第 {paging.PageIndex} 页,共 {Math.ceil(paging.TotalRecords / paging.PageSize)} 页
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 失信记录卡片组件 */
|
||||
interface DishonestyRecordCardProps {
|
||||
record: DishonestyRecord;
|
||||
index: number;
|
||||
}
|
||||
|
||||
function DishonestyRecordCard({ record, index }: DishonestyRecordCardProps) {
|
||||
return (
|
||||
<div className="border border-red-200 rounded-lg overflow-hidden">
|
||||
{/* 卡片头部 */}
|
||||
<div className="bg-red-50 px-4 py-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="bg-red-500 text-white text-xs px-2 py-0.5 rounded">
|
||||
#{index}
|
||||
</span>
|
||||
<span className="font-medium text-gray-800">{record.Anno || '案号未知'}</span>
|
||||
</div>
|
||||
<span className={`px-2 py-0.5 text-xs rounded-full border ${getExecuteStatusColor(record.Executestatus)}`}>
|
||||
{record.Executestatus || '状态未知'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 卡片内容 */}
|
||||
<div className="p-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<RecordItem
|
||||
icon="ri-bank-line"
|
||||
label="执行法院"
|
||||
value={record.Executegov}
|
||||
/>
|
||||
<RecordItem
|
||||
icon="ri-calendar-line"
|
||||
label="立案日期"
|
||||
value={formatDate(record.Liandate)}
|
||||
/>
|
||||
<RecordItem
|
||||
icon="ri-calendar-check-line"
|
||||
label="发布日期"
|
||||
value={formatDate(record.Publicdate)}
|
||||
/>
|
||||
<RecordItem
|
||||
icon="ri-money-cny-circle-line"
|
||||
label="涉案金额"
|
||||
value={formatAmount(record.Amount)}
|
||||
valueClassName="text-red-600 font-medium"
|
||||
/>
|
||||
<RecordItem
|
||||
icon="ri-file-text-line"
|
||||
label="执行依据文号"
|
||||
value={record.Executeno}
|
||||
className="md:col-span-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 失信行为 */}
|
||||
{record.ActionRemark && (
|
||||
<div className="mt-4">
|
||||
<div className="flex items-start gap-2">
|
||||
<i className="ri-error-warning-line text-red-500 mt-0.5"></i>
|
||||
<div className="flex-1">
|
||||
<span className="text-xs text-gray-500 block mb-1">失信行为</span>
|
||||
<p className="text-sm text-gray-700 bg-red-50 p-3 rounded-lg border border-red-100">
|
||||
{record.ActionRemark}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 记录项组件 */
|
||||
interface RecordItemProps {
|
||||
icon: string;
|
||||
label: string;
|
||||
value: string | null | undefined;
|
||||
className?: string;
|
||||
valueClassName?: string;
|
||||
}
|
||||
|
||||
function RecordItem({ icon, label, value, className = '', valueClassName = 'text-gray-800' }: RecordItemProps) {
|
||||
return (
|
||||
<div className={`flex items-start gap-2 ${className}`}>
|
||||
<i className={`${icon} text-gray-400 mt-0.5`}></i>
|
||||
<div className="flex-1 min-w-0">
|
||||
<span className="text-xs text-gray-500 block">{label}</span>
|
||||
<span className={`text-sm ${valueClassName} break-words`}>{value || '-'}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 企业信息组件导出文件
|
||||
*/
|
||||
|
||||
// 主组件
|
||||
export { CorporateInformation } from './CorporateInformation';
|
||||
export { BusinessInfo } from './BusinessInfo';
|
||||
export { DishonestyInfo } from './DishonestyInfo';
|
||||
export { CorporateInfoModal } from './CorporateInfoModal';
|
||||
export type { CorporateInfoModalProps } from './CorporateInfoModal';
|
||||
|
||||
// 类型导出
|
||||
export type {
|
||||
// 企业工商信息类型
|
||||
DesignatedRepresentative,
|
||||
OriginalName,
|
||||
RevokeInfo,
|
||||
Area,
|
||||
BusinessInfoResult,
|
||||
BusinessInfoResponse,
|
||||
BusinessInfoProps,
|
||||
// 失信核查类型
|
||||
DishonestyRecord,
|
||||
Paging,
|
||||
DishonestyResult,
|
||||
DishonestyResponse,
|
||||
DishonestyInfoProps,
|
||||
// 综合组件类型
|
||||
CorporateInformationProps,
|
||||
} from './types';
|
||||
|
||||
// 枚举和常量导出
|
||||
export { EntTypeEnum, EntTypeLabel, ExecuteStatusEnum } from './types';
|
||||
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* 企业工商信息和失信核查相关类型定义
|
||||
*/
|
||||
|
||||
// ==================== 企业工商信息类型 ====================
|
||||
|
||||
/** 委派代表 */
|
||||
export interface DesignatedRepresentative {
|
||||
/** 合伙人名称 */
|
||||
PartnerName: string;
|
||||
/** 委派代表名称 */
|
||||
DelegatedName: string;
|
||||
}
|
||||
|
||||
/** 曾用名 */
|
||||
export interface OriginalName {
|
||||
/** 曾用名 */
|
||||
Name: string;
|
||||
/** 变更日期 */
|
||||
ChangeDate: string;
|
||||
}
|
||||
|
||||
/** 注销吊销信息 */
|
||||
export interface RevokeInfo {
|
||||
/** 注销日期 */
|
||||
CancelDate: string;
|
||||
/** 注销原因 */
|
||||
CancelReason: string;
|
||||
/** 吊销日期 */
|
||||
RevokeDate: string;
|
||||
/** 吊销原因 */
|
||||
RevokeReason: string;
|
||||
}
|
||||
|
||||
/** 行政区域 */
|
||||
export interface Area {
|
||||
/** 省份 */
|
||||
Province: string;
|
||||
/** 城市 */
|
||||
City: string;
|
||||
/** 区域 */
|
||||
County: string;
|
||||
}
|
||||
|
||||
/** 企业性质枚举 */
|
||||
export enum EntTypeEnum {
|
||||
/** 大陆企业 */
|
||||
MainlandEnterprise = '0',
|
||||
/** 社会组织 */
|
||||
SocialOrganization = '1',
|
||||
/** 事业单位 */
|
||||
PublicInstitution = '4',
|
||||
/** 医院 */
|
||||
Hospital = '7',
|
||||
/** 律师事务所 */
|
||||
LawFirm = '9',
|
||||
/** 学校 */
|
||||
School = '10',
|
||||
/** 机关单位 */
|
||||
GovernmentOrgan = '11',
|
||||
/** 其他 */
|
||||
Other = '-1',
|
||||
}
|
||||
|
||||
/** 企业性质显示映射 */
|
||||
export const EntTypeLabel: Record<string, string> = {
|
||||
'0': '大陆企业',
|
||||
'1': '社会组织',
|
||||
'4': '事业单位',
|
||||
'7': '医院',
|
||||
'9': '律师事务所',
|
||||
'10': '学校',
|
||||
'11': '机关单位',
|
||||
'-1': '其他',
|
||||
};
|
||||
|
||||
/** 企业工商信息结果 */
|
||||
export interface BusinessInfoResult {
|
||||
/** 主键 */
|
||||
KeyNo: string;
|
||||
/** 企业名称 */
|
||||
Name: string;
|
||||
/** 工商注册号/企业编号 */
|
||||
No: string;
|
||||
/** 登记机关 */
|
||||
BelongOrg: string;
|
||||
/** 法定代表人ID */
|
||||
OperId: string;
|
||||
/** 法定代表人名称 */
|
||||
OperName: string;
|
||||
/** 委派代表列表 */
|
||||
DesignatedRepresentativeList: DesignatedRepresentative[];
|
||||
/** 成立日期 */
|
||||
StartDate: string;
|
||||
/** 吊销日期(保留字段) */
|
||||
EndDate: string;
|
||||
/** 登记状态 */
|
||||
Status: string;
|
||||
/** 省份(缩写) */
|
||||
Province: string;
|
||||
/** 更新日期 */
|
||||
UpdatedDate: string;
|
||||
/** 统一社会信用代码/商业登记号码 */
|
||||
CreditCode: string;
|
||||
/** 注册资本(含单位) */
|
||||
RegistCapi: string;
|
||||
/** 注册资本数额 */
|
||||
RegisteredCapital: string;
|
||||
/** 注册资本单位 */
|
||||
RegisteredCapitalUnit: string;
|
||||
/** 注册资本币种 */
|
||||
RegisteredCapitalCCY: string;
|
||||
/** 实缴资本(含单位) */
|
||||
RecCap: string;
|
||||
/** 实缴出资额数额 */
|
||||
PaidUpCapital: string;
|
||||
/** 实缴出资额单位 */
|
||||
PaidUpCapitalUnit: string;
|
||||
/** 实缴出资额币种 */
|
||||
PaidUpCapitalCCY: string;
|
||||
/** 企业类型 */
|
||||
EconKind: string;
|
||||
/** 注册地址 */
|
||||
Address: string;
|
||||
/** 经营范围 */
|
||||
Scope: string;
|
||||
/** 营业期限始 */
|
||||
TermStart: string;
|
||||
/** 营业期限至 */
|
||||
TermEnd: string;
|
||||
/** 核准日期 */
|
||||
CheckDate: string;
|
||||
/** 组织机构代码 */
|
||||
OrgNo: string;
|
||||
/** 是否上市(0-未上市,1-上市) */
|
||||
IsOnStock: string;
|
||||
/** 股票代码 */
|
||||
StockNumber: string | null;
|
||||
/** 上市类型 */
|
||||
StockType: string | null;
|
||||
/** 曾用名列表 */
|
||||
OriginalName: OriginalName[];
|
||||
/** 企业Logo地址 */
|
||||
ImageUrl: string;
|
||||
/** 企业性质 */
|
||||
EntType: string;
|
||||
/** 注销吊销信息 */
|
||||
RevokeInfo: RevokeInfo | null;
|
||||
/** 行政区域 */
|
||||
Area: Area | null;
|
||||
/** 行政区划代码 */
|
||||
AreaCode: string;
|
||||
}
|
||||
|
||||
/** 企业工商信息响应 */
|
||||
export interface BusinessInfoResponse {
|
||||
/** 查询结果数据 */
|
||||
Result: BusinessInfoResult | null;
|
||||
/** 状态码(200 表示成功) */
|
||||
Status: string;
|
||||
/** 响应消息 */
|
||||
Message: string;
|
||||
/** 订单编号 */
|
||||
OrderNumber: string;
|
||||
}
|
||||
|
||||
// ==================== 失信核查类型 ====================
|
||||
|
||||
/** 失信记录数据 */
|
||||
export interface DishonestyRecord {
|
||||
/** 主键 */
|
||||
Id: string;
|
||||
/** 立案日期 */
|
||||
Liandate: string;
|
||||
/** 案号 */
|
||||
Anno: string;
|
||||
/** 执行法院 */
|
||||
Executegov: string;
|
||||
/** 被执行人的履行情况 */
|
||||
Executestatus: string;
|
||||
/** 发布日期 */
|
||||
Publicdate: string;
|
||||
/** 执行依据文号 */
|
||||
Executeno: string;
|
||||
/** 失信行为 */
|
||||
ActionRemark: string;
|
||||
/** 涉案金额(元) */
|
||||
Amount: string;
|
||||
}
|
||||
|
||||
/** 分页信息 */
|
||||
export interface Paging {
|
||||
/** 每页记录数 */
|
||||
PageSize: number;
|
||||
/** 当前页码 */
|
||||
PageIndex: number;
|
||||
/** 总记录数 */
|
||||
TotalRecords: number;
|
||||
}
|
||||
|
||||
/** 失信核查结果 */
|
||||
export interface DishonestyResult {
|
||||
/** 数据是否存在(1-存在,0-不存在) */
|
||||
VerifyResult: number;
|
||||
/** 数据信息列表 */
|
||||
Data: DishonestyRecord[];
|
||||
}
|
||||
|
||||
/** 失信核查响应 */
|
||||
export interface DishonestyResponse {
|
||||
/** 分页信息 */
|
||||
Paging: Paging;
|
||||
/** 查询结果数据 */
|
||||
Result: DishonestyResult | null;
|
||||
/** 状态码(200 表示成功) */
|
||||
Status: string;
|
||||
/** 响应消息 */
|
||||
Message: string;
|
||||
/** 订单编号 */
|
||||
OrderNumber: string;
|
||||
}
|
||||
|
||||
/** 履行情况枚举 */
|
||||
export enum ExecuteStatusEnum {
|
||||
/** 全部未履行 */
|
||||
NotExecuted = '全部未履行',
|
||||
/** 部分履行 */
|
||||
PartiallyExecuted = '部分履行',
|
||||
/** 全部履行 */
|
||||
FullyExecuted = '全部履行',
|
||||
}
|
||||
|
||||
// ==================== 组件Props类型 ====================
|
||||
|
||||
/** 企业工商信息组件Props */
|
||||
export interface BusinessInfoProps {
|
||||
/** 企业工商信息数据 */
|
||||
data: BusinessInfoResult | null;
|
||||
/** 是否加载中 */
|
||||
loading?: boolean;
|
||||
/** 错误信息 */
|
||||
error?: string | null;
|
||||
}
|
||||
|
||||
/** 失信核查组件Props */
|
||||
export interface DishonestyInfoProps {
|
||||
/** 失信核查数据 */
|
||||
data: DishonestyResult | null;
|
||||
/** 分页信息 */
|
||||
paging?: Paging | null;
|
||||
/** 是否加载中 */
|
||||
loading?: boolean;
|
||||
/** 错误信息 */
|
||||
error?: string | null;
|
||||
}
|
||||
|
||||
/** 企业综合信息组件Props */
|
||||
export interface CorporateInformationProps {
|
||||
/** 企业工商信息 */
|
||||
businessInfo: BusinessInfoResult | null;
|
||||
/** 失信核查数据 */
|
||||
dishonestyInfo: DishonestyResult | null;
|
||||
/** 失信核查分页信息 */
|
||||
dishonestyPaging?: Paging | null;
|
||||
/** 企业工商信息加载中 */
|
||||
businessLoading?: boolean;
|
||||
/** 失信核查加载中 */
|
||||
dishonestyLoading?: boolean;
|
||||
/** 企业工商信息错误 */
|
||||
businessError?: string | null;
|
||||
/** 失信核查错误 */
|
||||
dishonestyError?: string | null;
|
||||
}
|
||||
@@ -21,6 +21,9 @@ import { useState, useEffect, useRef } from 'react';
|
||||
import { toastService } from '../ui/Toast';
|
||||
import { createPortal } from 'react-dom'; // 导入React Portal API,用于将组件渲染到DOM树的不同位置
|
||||
import { Tooltip } from '../ui/Tooltip';
|
||||
import { CorporateInfoModal } from '../corporate-information';
|
||||
import type { BusinessInfoResult, DishonestyResult } from '../corporate-information';
|
||||
import { queryCompanyInfo } from '~/api/corporate-information/qichacha';
|
||||
// import '../../styles/components/TooltipStyles.css';
|
||||
|
||||
/**
|
||||
@@ -423,6 +426,15 @@ export function ReviewPointsList({
|
||||
// 存放评查点ID与有效页码的映射
|
||||
const [effectivePages, setEffectivePages] = useState<Record<string, number>>({});
|
||||
|
||||
// 企业信息模态框状态
|
||||
const [corporateModalVisible, setCorporateModalVisible] = useState(false);
|
||||
const [corporateCompanyName, setCorporateCompanyName] = useState('');
|
||||
const [corporateBusinessInfo, setCorporateBusinessInfo] = useState<BusinessInfoResult | null>(null);
|
||||
const [corporateDishonestyInfo, setCorporateDishonestyInfo] = useState<DishonestyResult | null>(null);
|
||||
const [corporateLoading, setCorporateLoading] = useState(false);
|
||||
const [corporateError, setCorporateError] = useState<string | null>(null);
|
||||
const [corporateUpdatedAt, setCorporateUpdatedAt] = useState<string | null>(null);
|
||||
|
||||
// 初始化建议文本
|
||||
useEffect(() => {
|
||||
// 使用函数式更新,不再需要外部 manualReviewNotes 变量
|
||||
@@ -483,6 +495,71 @@ export function ReviewPointsList({
|
||||
setEditingReviewPoint(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理企业信息按钮点击
|
||||
* @param companyName 企业名称(乙方名称)
|
||||
* @param forceRefresh 是否强制刷新(对接企查查重新查询)
|
||||
*/
|
||||
const handleCorporateInfoClick = async (companyName: string, forceRefresh = false) => {
|
||||
if (!companyName) {
|
||||
toastService.warning('企业名称为空,无法查询');
|
||||
return;
|
||||
}
|
||||
|
||||
// 打开模态框并设置加载状态
|
||||
setCorporateModalVisible(true);
|
||||
setCorporateCompanyName(companyName);
|
||||
setCorporateLoading(true);
|
||||
setCorporateError(null);
|
||||
setCorporateBusinessInfo(null);
|
||||
setCorporateDishonestyInfo(null);
|
||||
setCorporateUpdatedAt(null);
|
||||
|
||||
try {
|
||||
const response = await queryCompanyInfo({ keyword: companyName, force_refresh: forceRefresh });
|
||||
|
||||
if (response.success && response.data) {
|
||||
setCorporateBusinessInfo(response.data.enterprise);
|
||||
setCorporateUpdatedAt(response.data.updated_at);
|
||||
// 转换失信数据格式
|
||||
if (response.data.dishonesty) {
|
||||
setCorporateDishonestyInfo({
|
||||
VerifyResult: response.data.dishonesty.VerifyResult,
|
||||
Data: response.data.dishonesty.Data || [],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setCorporateError(response.message || '查询失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询企业信息失败:', error);
|
||||
setCorporateError(error instanceof Error ? error.message : '查询失败');
|
||||
} finally {
|
||||
setCorporateLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理强制刷新(对接企查查重新查询)
|
||||
*/
|
||||
const handleCorporateForceRefresh = async () => {
|
||||
if (corporateCompanyName) {
|
||||
await handleCorporateInfoClick(corporateCompanyName, true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭企业信息模态框
|
||||
*/
|
||||
const handleCloseCorporateModal = () => {
|
||||
setCorporateModalVisible(false);
|
||||
setCorporateCompanyName('');
|
||||
setCorporateBusinessInfo(null);
|
||||
setCorporateDishonestyInfo(null);
|
||||
setCorporateError(null);
|
||||
setCorporateUpdatedAt(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* 过滤评查点
|
||||
* 根据搜索文本和状态过滤条件筛选评查点
|
||||
@@ -2406,7 +2483,7 @@ export function ReviewPointsList({
|
||||
tabIndex={0}
|
||||
style={{ userSelect: 'text' }}
|
||||
onClick={() => {
|
||||
// console.log('reviewPoint', reviewPoint);
|
||||
console.log('reviewPoint', reviewPoint);
|
||||
handleReviewPointClick(reviewPoint.id);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
@@ -2419,7 +2496,51 @@ export function ReviewPointsList({
|
||||
{/* 评查点名称 pointName*/}
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
{/* <div className='flex flex-col'> */}
|
||||
<div className="review-point-title text-left text-blue-500 max-w-[75%] break-all">{reviewPoint.pointName}</div>
|
||||
<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>
|
||||
{ reviewPoint.pointName === '签署乙方详细信息校验' && (
|
||||
<button
|
||||
className="enterprise-info-btn"
|
||||
style={{
|
||||
padding: '2px 8px',
|
||||
fontSize: '12px',
|
||||
borderRadius: '4px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
flexShrink: 0,
|
||||
transition: 'all 0.2s',
|
||||
border: 'none',
|
||||
cursor: reviewPoint.content?.['合同主体信息-乙方-名称']?.value ? 'pointer' : 'not-allowed',
|
||||
backgroundColor: reviewPoint.content?.['合同主体信息-乙方-名称']?.value ? '#00684a' : '#e5e7eb',
|
||||
color: reviewPoint.content?.['合同主体信息-乙方-名称']?.value ? '#ffffff' : '#9ca3af',
|
||||
}}
|
||||
disabled={!reviewPoint.content?.['合同主体信息-乙方-名称']?.value}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
const companyNameValue = reviewPoint.content?.['合同主体信息-乙方-名称']?.value;
|
||||
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
|
||||
if (companyName) {
|
||||
handleCorporateInfoClick(companyName);
|
||||
}
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (reviewPoint.content?.['合同主体信息-乙方-名称']?.value) {
|
||||
e.currentTarget.style.backgroundColor = '#005a3f';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (reviewPoint.content?.['合同主体信息-乙方-名称']?.value) {
|
||||
e.currentTarget.style.backgroundColor = '#00684a';
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
企业信息
|
||||
</button>
|
||||
)}
|
||||
|
||||
</div>
|
||||
{/* <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>
|
||||
//评查点分组显示
|
||||
@@ -2450,6 +2571,21 @@ export function ReviewPointsList({
|
||||
renderEmptyState()
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 企业信息模态框 */}
|
||||
<CorporateInfoModal
|
||||
visible={corporateModalVisible}
|
||||
onClose={handleCloseCorporateModal}
|
||||
companyName={corporateCompanyName}
|
||||
businessInfo={corporateBusinessInfo}
|
||||
dishonestyInfo={corporateDishonestyInfo}
|
||||
businessLoading={corporateLoading}
|
||||
dishonestyLoading={corporateLoading}
|
||||
businessError={corporateError}
|
||||
dishonestyError={corporateError}
|
||||
updatedAt={corporateUpdatedAt}
|
||||
onForceRefresh={handleCorporateForceRefresh}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user