完成五人团队正式内用最小收口(07-18-small-team-internal-readiness)
这个提交包含在:
@@ -37,9 +37,9 @@ const STATUS_OPTIONS: Array<{ value: "" | WecomApprovalArchiveStatus; label: str
|
||||
|
||||
const FINDING_OPTIONS: Array<{ value: "" | WecomApprovalArchiveFinding; label: string }> = [
|
||||
{ value: "", label: "全部对账" },
|
||||
{ value: "open", label: "仅未关闭 finding" },
|
||||
{ value: "resolved", label: "已关闭 finding" },
|
||||
{ value: "any", label: "有 finding" },
|
||||
{ value: "open", label: "仅未关闭问题" },
|
||||
{ value: "resolved", label: "已关闭问题" },
|
||||
{ value: "any", label: "有对账问题" },
|
||||
];
|
||||
|
||||
function resolveError(error: unknown, fallback = "读取企微审批历史失败") {
|
||||
@@ -121,7 +121,7 @@ function ArchiveRow({
|
||||
<td className="px-3 py-3 align-top text-sm text-zinc-600">{formatTime(item.statusObservedAt || item.completedAt || item.appliedAt)}</td>
|
||||
<td className="px-3 py-3 align-top text-sm text-zinc-600">
|
||||
<div>{sourceLabel(item.lastSource)}</div>
|
||||
{item.openFindingCount ? <div className="mt-1 text-xs text-amber-700">finding {item.openFindingCount} 项</div> : null}
|
||||
{item.openFindingCount ? <div className="mt-1 text-xs text-amber-700">对账问题 {item.openFindingCount} 项</div> : null}
|
||||
</td>
|
||||
<td className="px-3 py-3 align-top text-right">
|
||||
<Button type="button" variant="secondary" onClick={onSelect}>查看历史</Button>
|
||||
@@ -156,7 +156,7 @@ export function WecomApprovalArchivePage() {
|
||||
const detail = detailQuery.data?.item ?? null;
|
||||
|
||||
return (
|
||||
<div className="page-shell space-y-6" data-testid="wecom-approval-archive-page">
|
||||
<div className="page-shell min-w-0 max-w-full space-y-6" data-testid="wecom-approval-archive-page">
|
||||
<PageHeader
|
||||
eyebrow="企微审批历史"
|
||||
title="企微审批历史"
|
||||
@@ -219,7 +219,7 @@ export function WecomApprovalArchivePage() {
|
||||
{listQuery.isError ? <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">{resolveError(listQuery.error)}</div> : null}
|
||||
{!listQuery.isLoading && !listQuery.isError && !items.length ? (
|
||||
<div className="rounded-md border border-dashed border-slate-300 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500">
|
||||
暂无已归档的企微审批历史。若公网 OA DB 还没有留存数据,验收记录为 PARTIAL_ARCHIVE_NEEDS_DATA。
|
||||
暂无已归档的企微审批历史;如数据尚未同步,可稍后重试或联系管理员核对归档状态。
|
||||
</div>
|
||||
) : null}
|
||||
{!listQuery.isLoading && !listQuery.isError && items.length ? (
|
||||
@@ -245,17 +245,17 @@ export function WecomApprovalArchivePage() {
|
||||
</div>
|
||||
<div className="divide-y divide-slate-100 md:hidden">
|
||||
{items.map((item) => (
|
||||
<article className="py-3" key={item.id}>
|
||||
<article className="min-w-0 py-3" key={item.id}>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="font-medium text-zinc-900">{typeLabel(item.templateType)}</div>
|
||||
<div className="mt-1 text-xs text-zinc-500">单号前缀:{item.spNoPrefix || "-"}</div>
|
||||
<div className="mt-1 break-all text-xs text-zinc-500">单号前缀:{item.spNoPrefix || "-"}</div>
|
||||
</div>
|
||||
<StatusBadge status={item.normalizedStatus} />
|
||||
</div>
|
||||
<div className="mt-2 text-sm text-zinc-600">{employeeLabel(item.applicant)} · {formatTime(item.statusObservedAt || item.completedAt || item.appliedAt)}</div>
|
||||
<div className="mt-2 break-words text-sm text-zinc-600 [overflow-wrap:anywhere]">{employeeLabel(item.applicant)} · {formatTime(item.statusObservedAt || item.completedAt || item.appliedAt)}</div>
|
||||
<div className="mt-2 flex items-center justify-between gap-3">
|
||||
<span className="text-xs text-zinc-500">{sourceLabel(item.lastSource)}{item.openFindingCount ? ` · finding ${item.openFindingCount}` : ""}</span>
|
||||
<span className="min-w-0 break-words text-xs text-zinc-500 [overflow-wrap:anywhere]">{sourceLabel(item.lastSource)}{item.openFindingCount ? ` · 对账问题 ${item.openFindingCount}` : ""}</span>
|
||||
<Button type="button" variant="secondary" onClick={() => setSelectedId(item.id)}>查看历史</Button>
|
||||
</div>
|
||||
</article>
|
||||
@@ -273,30 +273,30 @@ export function WecomApprovalArchivePage() {
|
||||
{selectedId && detailQuery.isLoading ? <TableSkeleton columns={1} rows={3} /> : null}
|
||||
{selectedId && detailQuery.isError ? <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">{resolveError(detailQuery.error)}</div> : null}
|
||||
{detail ? (
|
||||
<div className="grid gap-4 lg:grid-cols-3">
|
||||
<div className="space-y-3 lg:col-span-1">
|
||||
<div className="grid min-w-0 max-w-full gap-4 lg:grid-cols-3">
|
||||
<div className="min-w-0 space-y-3 lg:col-span-1">
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">状态</div>
|
||||
<div className="mt-1"><StatusBadge status={detail.normalizedStatus} /></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">申请人</div>
|
||||
<div className="mt-1 text-sm text-zinc-800">{employeeLabel(detail.applicant)}</div>
|
||||
<div className="mt-1 break-words text-sm text-zinc-800 [overflow-wrap:anywhere]">{employeeLabel(detail.applicant)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-zinc-500">单号前缀</div>
|
||||
<div className="mt-1 text-sm text-zinc-800">{detail.spNoPrefix || "-"}</div>
|
||||
<div className="mt-1 break-all text-sm text-zinc-800">{detail.spNoPrefix || "-"}</div>
|
||||
</div>
|
||||
{detail.singleTapApproveRisk ? <div className="rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800">企微同意可能单击即通过,OA 仅留存动作来源和历史审计。</div> : null}
|
||||
</div>
|
||||
<div className="space-y-4 lg:col-span-2">
|
||||
<div className="min-w-0 space-y-4 lg:col-span-2">
|
||||
<div>
|
||||
<h4 className="text-sm font-semibold text-zinc-900">字段摘要</h4>
|
||||
<div className="mt-2 divide-y divide-slate-100 rounded-md border border-slate-200">
|
||||
{detail.fields.length ? detail.fields.map((field) => (
|
||||
<div className="grid gap-1 px-3 py-2 text-sm md:grid-cols-3" key={field.id}>
|
||||
<span className="font-medium text-zinc-800">{field.fieldName || field.fieldKey}</span>
|
||||
<span className="text-zinc-500">{field.fieldType || "-"}</span>
|
||||
<div className="grid min-w-0 gap-1 px-3 py-2 text-sm md:grid-cols-3" key={field.id}>
|
||||
<span className="min-w-0 break-words font-medium text-zinc-800 [overflow-wrap:anywhere]">{field.fieldName || field.fieldKey}</span>
|
||||
<span className="min-w-0 break-words text-zinc-500 [overflow-wrap:anywhere]">{field.fieldType || "-"}</span>
|
||||
<span className="text-zinc-500">{field.sensitiveLevel === "restricted" ? "受限字段" : "普通字段"}</span>
|
||||
</div>
|
||||
)) : <div className="px-3 py-3 text-sm text-zinc-500">暂无字段摘要。</div>}
|
||||
@@ -309,7 +309,7 @@ export function WecomApprovalArchivePage() {
|
||||
{detail.participants.length ? detail.participants.map((item) => (
|
||||
<div className="border-b border-slate-100 px-3 py-2 text-sm last:border-b-0" key={item.id}>
|
||||
<span className="font-medium text-zinc-800">{roleLabel(item.role)}</span>
|
||||
<span className="ml-2 text-zinc-600">{employeeLabel(item.employee)}</span>
|
||||
<span className="ml-2 break-words text-zinc-600 [overflow-wrap:anywhere]">{employeeLabel(item.employee)}</span>
|
||||
</div>
|
||||
)) : <div className="px-3 py-3 text-sm text-zinc-500">暂无映射参与人。</div>}
|
||||
</div>
|
||||
@@ -317,7 +317,7 @@ export function WecomApprovalArchivePage() {
|
||||
{detail.actions.length ? detail.actions.map((item) => (
|
||||
<div className="border-b border-slate-100 px-3 py-2 text-sm last:border-b-0" key={item.id}>
|
||||
<span className="font-medium text-zinc-800">{actionLabel(item.actionType)}</span>
|
||||
<span className="ml-2 text-zinc-600">{employeeLabel(item.operator)}</span>
|
||||
<span className="ml-2 break-words text-zinc-600 [overflow-wrap:anywhere]">{employeeLabel(item.operator)}</span>
|
||||
<div className="mt-1 text-xs text-zinc-500">{formatTime(item.actionTime)} · {sourceLabel(item.source)}</div>
|
||||
</div>
|
||||
)) : <div className="px-3 py-3 text-sm text-zinc-500">暂无动作历史。</div>}
|
||||
@@ -325,14 +325,14 @@ export function WecomApprovalArchivePage() {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-semibold text-zinc-900">对账 finding</h4>
|
||||
<h4 className="text-sm font-semibold text-zinc-900">对账问题</h4>
|
||||
<div className="mt-2 divide-y divide-slate-100 rounded-md border border-slate-200">
|
||||
{detail.findings.length ? detail.findings.map((item) => (
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 px-3 py-2 text-sm" key={item.id}>
|
||||
<span className="font-medium text-zinc-800">{item.findingType}</span>
|
||||
<span className="text-zinc-500">{item.status} · {item.severity} · {formatTime(item.detectedAt)}</span>
|
||||
<span className="min-w-0 break-words font-medium text-zinc-800 [overflow-wrap:anywhere]">{item.findingType}</span>
|
||||
<span className="min-w-0 break-words text-zinc-500 [overflow-wrap:anywhere]">{item.status} · {item.severity} · {formatTime(item.detectedAt)}</span>
|
||||
</div>
|
||||
)) : <div className="px-3 py-3 text-sm text-zinc-500">暂无对账 finding。</div>}
|
||||
)) : <div className="px-3 py-3 text-sm text-zinc-500">暂无对账问题。</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
在新工单中引用
屏蔽一个用户