244 lines
10 KiB
TypeScript
244 lines
10 KiB
TypeScript
import type { Dispatch, SetStateAction } from 'react';
|
|
import { ChevronDown, ChevronRight, Edit3, Plus } from 'lucide-react';
|
|
import type { ClientSmsSignature } from '@/api/adminApi';
|
|
import { Button, DeleteRiskAction, Pagination } from '@/components/ui';
|
|
import {
|
|
AuditStatusTag,
|
|
CarrierReportCount,
|
|
formatSignatureName,
|
|
readDrainagePayload,
|
|
signatureCardVisual,
|
|
} from './signature.helpers';
|
|
import type { DrainageInfo } from './signature.types';
|
|
|
|
type EnterpriseSignaturesTableProps = {
|
|
appliedDrainageKeyword: string;
|
|
currentPage: number;
|
|
expandedSignatureId: string;
|
|
filteredSignatures: ClientSmsSignature[];
|
|
loadData: () => Promise<void>;
|
|
onAddDrainage: (signature: ClientSmsSignature) => void;
|
|
setDeleteTarget: Dispatch<SetStateAction<{ kind: 'drainage'; signatureId: string; id: string; name: string } | null>>;
|
|
onEditDrainage: (signature: ClientSmsSignature, item: DrainageInfo) => void;
|
|
onOpenDrainageReport: (signature: ClientSmsSignature, item: DrainageInfo) => void;
|
|
setExpandedSignatureId: Dispatch<SetStateAction<string>>;
|
|
setPage: Dispatch<SetStateAction<number>>;
|
|
onEditSignature: (signature: ClientSmsSignature) => void;
|
|
onOpenSignatureReport: (signature: ClientSmsSignature) => void;
|
|
total: number;
|
|
totalPages: number;
|
|
visibleSignatures: ClientSmsSignature[];
|
|
};
|
|
|
|
export function EnterpriseSignaturesTable({
|
|
appliedDrainageKeyword,
|
|
currentPage,
|
|
expandedSignatureId,
|
|
filteredSignatures,
|
|
loadData,
|
|
onAddDrainage,
|
|
setDeleteTarget,
|
|
onEditDrainage,
|
|
onOpenDrainageReport,
|
|
setExpandedSignatureId,
|
|
setPage,
|
|
onEditSignature,
|
|
onOpenSignatureReport,
|
|
total,
|
|
totalPages,
|
|
visibleSignatures,
|
|
}: EnterpriseSignaturesTableProps) {
|
|
return (
|
|
<div className="signature-list admin-enterprise-signature-list">
|
|
<div className="enterprise-signature-table__head" role="row">
|
|
<span aria-hidden="true" />
|
|
<span>签名</span>
|
|
<span>企业</span>
|
|
<span>应用</span>
|
|
<span>审核状态</span>
|
|
<span>移动</span>
|
|
<span>联通</span>
|
|
<span>电信</span>
|
|
<span>引流信息</span>
|
|
<span>操作</span>
|
|
</div>
|
|
{visibleSignatures.map((signature) => {
|
|
const payload = readDrainagePayload(signature);
|
|
const visibleDrainageLinks = appliedDrainageKeyword
|
|
? payload.links.filter((item) =>
|
|
`${item.siteName} ${item.url} ${item.remark}`.includes(appliedDrainageKeyword),
|
|
)
|
|
: payload.links;
|
|
const cardVisual = signatureCardVisual(signature.auditStatus, signature.carrierReportSummary);
|
|
const expanded = expandedSignatureId === signature.id || Boolean(appliedDrainageKeyword);
|
|
const signatureTooltip = [
|
|
`签名:${formatSignatureName(signature.name)}`,
|
|
`企业:${signature.tenant?.name ?? signature.tenantId}`,
|
|
`应用:${signature.application?.name ?? '未绑定应用'}`,
|
|
`用途:${signature.purpose || '未填写'}`,
|
|
`审核状态:${signature.auditStatus}`,
|
|
`创建时间:${signature.createdAt ? new Date(signature.createdAt).toLocaleString('zh-CN') : '未知'}`,
|
|
`更新时间:${signature.updatedAt ? new Date(signature.updatedAt).toLocaleString('zh-CN') : '未知'}`,
|
|
].join('\n');
|
|
return (
|
|
<article
|
|
aria-label={`签名总体状态:${cardVisual.label}`}
|
|
className={`signature-card signature-card--${cardVisual.tone}`}
|
|
key={signature.id}
|
|
title={`总体状态:${cardVisual.label}`}
|
|
>
|
|
<div className="signature-summary">
|
|
<button
|
|
aria-label="展开签名"
|
|
onClick={() => setExpandedSignatureId(expanded ? '' : signature.id)}
|
|
type="button"
|
|
>
|
|
{expanded ? <ChevronDown size={18} /> : <ChevronRight size={18} />}
|
|
</button>
|
|
<div aria-label={signatureTooltip} className="enterprise-signature-table__signature" data-label="签名" title={signatureTooltip}>
|
|
<strong>{formatSignatureName(signature.name)}</strong>
|
|
</div>
|
|
<div data-label="企业">
|
|
<span className="signature-summary__regular-value">{signature.tenant?.name ?? signature.tenantId}</span>
|
|
</div>
|
|
<div data-label="应用">
|
|
<span className="signature-summary__regular-value">{signature.application?.name ?? '-'}</span>
|
|
</div>
|
|
<div data-label="审核状态">
|
|
<AuditStatusTag status={signature.auditStatus} />
|
|
</div>
|
|
<div data-label="移动">
|
|
<CarrierReportCount summary={signature.carrierReportSummary?.mobile} />
|
|
</div>
|
|
<div data-label="联通">
|
|
<CarrierReportCount summary={signature.carrierReportSummary?.unicom} />
|
|
</div>
|
|
<div data-label="电信">
|
|
<CarrierReportCount summary={signature.carrierReportSummary?.telecom} />
|
|
</div>
|
|
<div data-label="引流信息">
|
|
<strong>{payload.links.length} 条</strong>
|
|
</div>
|
|
<div className="signature-actions">
|
|
<Button
|
|
className="enterprise-signature-action-button"
|
|
icon={<Edit3 size={16} />}
|
|
onClick={() => onOpenSignatureReport(signature)}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
报备状态
|
|
</Button>
|
|
<Button
|
|
className="enterprise-signature-action-button"
|
|
icon={<Edit3 size={16} />}
|
|
onClick={() => onEditSignature(signature)}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
编辑
|
|
</Button>
|
|
<DeleteRiskAction
|
|
className="enterprise-signature-action-button"
|
|
onCompleted={() => void loadData()}
|
|
portal="admin"
|
|
targetId={signature.id}
|
|
targetType="signature"
|
|
/>
|
|
</div>
|
|
</div>
|
|
{expanded ? (
|
|
<div className="drainage-panel">
|
|
<h2>引流信息列表</h2>
|
|
{visibleDrainageLinks.length ? (
|
|
<div className="drainage-table">
|
|
<div className="drainage-table__head">
|
|
<span>引流url或号码</span>
|
|
<span>审核状态</span>
|
|
<span>移动</span>
|
|
<span>联通</span>
|
|
<span>电信</span>
|
|
<span>操作</span>
|
|
</div>
|
|
{visibleDrainageLinks.map((item) => {
|
|
const summary = signature.drainageCarrierReportSummary?.[item.id];
|
|
return (
|
|
<div className="drainage-table__row" key={item.id}>
|
|
<span className="drainage-table__url" title={item.url}>
|
|
{item.url}
|
|
</span>
|
|
<AuditStatusTag status={item.auditStatus ?? 'pending'} />
|
|
<CarrierReportCount summary={summary?.mobile} />
|
|
<CarrierReportCount summary={summary?.unicom} />
|
|
<CarrierReportCount summary={summary?.telecom} />
|
|
<span className="drainage-row-actions">
|
|
<Button
|
|
className="enterprise-signature-action-button"
|
|
disabled={item.auditStatus !== 'approved'}
|
|
onClick={() => onOpenDrainageReport(signature, item)}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
报备状态
|
|
</Button>
|
|
<Button
|
|
className="enterprise-signature-action-button"
|
|
onClick={() => onEditDrainage(signature, item)}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
编辑
|
|
</Button>
|
|
<Button
|
|
className="enterprise-signature-action-button"
|
|
onClick={() =>
|
|
setDeleteTarget({
|
|
kind: 'drainage',
|
|
signatureId: signature.id,
|
|
id: item.id,
|
|
name: item.url,
|
|
})
|
|
}
|
|
size="sm"
|
|
variant="danger"
|
|
>
|
|
删除
|
|
</Button>
|
|
</span>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
) : (
|
|
<p className="muted">暂无引流信息</p>
|
|
)}
|
|
<div className="drainage-panel__footer">
|
|
<Button
|
|
icon={<Plus size={16} />}
|
|
onClick={() => onAddDrainage(signature)}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
添加引流信息
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</article>
|
|
);
|
|
})}
|
|
<Pagination
|
|
nextDisabled={currentPage >= totalPages}
|
|
onNext={() => setPage((value) => Math.min(totalPages, value + 1))}
|
|
onPrevious={() => setPage((value) => Math.max(1, value - 1))}
|
|
page={currentPage}
|
|
totalPages={totalPages}
|
|
onPageChange={setPage}
|
|
previousDisabled={currentPage <= 1}
|
|
total={total}
|
|
/>
|
|
{filteredSignatures.length === 0 ? <div className="ui-table__empty">暂无企业签名</div> : null}
|
|
</div>
|
|
);
|
|
}
|