@hkyhy/marsun-components-core 0.1.118 → 0.1.119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"AuditLogList.js","sources":["../../../src/components/Audit/AuditLogList.tsx"],"sourcesContent":["import { CommonDescriptions } from '@/components/Descriptions';\nimport InfoPage from '@/components/InfoPage';\nimport { StatCardList, type StatItem } from '@/components/Stat';\nimport { Table } from '@/components/Table';\nimport { SEMANTIC_COLORS, SemanticTag } from '@/components/Tag';\nimport { VirtualScrollbar } from '@/components/VirtualScrollbar';\nimport { copyText } from '@/utils/copyText';\nimport { Button, Collapse, Empty, Space, Typography, message } from 'antd';\nimport type { ColumnsType } from 'antd/es/table';\nimport classNames from 'classnames';\nimport dayjs from 'dayjs';\nimport React, { useMemo } from 'react';\nimport { AuditDayStatsBar } from './AuditDayStatsBar';\nimport { AuditWaterfall } from './AuditWaterfall';\nimport { computeDetailKpi, isErrorStep } from './detailKpi';\nimport { formatAuditJson, isTruncatedAuditText } from './formatAuditJson';\nimport { buildAuditReplayCurl, readBrowserReplaySession } from './formatAuditCurl';\nimport { displayActionLabel, displaySummary, labelOfAction } from './labels';\nimport styles from './style.module.scss';\nimport type { AuditDayStats, AuditEventDetail, AuditEventListItem, AuditStep } from './types';\n\nexport type AuditLogListMode = 'app' | 'platform';\n\nexport type AuditLogListProps = {\n mode?: AuditLogListMode;\n dataSource: AuditEventListItem[];\n loading?: boolean;\n /** 点击行(进详情页) */\n onRowClick?: (row: AuditEventListItem) => void;\n filterSlot?: React.ReactNode;\n /** 日汇总顶栏 */\n dayStats?: AuditDayStats | null;\n dayStatsLoading?: boolean;\n dayStatsError?: string | null;\n onExport?: () => void;\n exportLoading?: boolean;\n pagination?: false | object;\n className?: string;\n /** platform 系统列:SSO SystemApp.code → name;缺则回落 systemAppId */\n systemAppNames?: Record<string, string>;\n};\n\nfunction formatCreatedAt(iso: string): string {\n const d = dayjs(iso);\n return d.isValid() ? d.format('YYYY-MM-DD HH:mm:ss') : iso;\n}\n\nfunction statusLabel(status: string): string {\n if (status === 'success') return '成功';\n if (status === 'fail' || status === 'error') return '失败';\n return status;\n}\n\nfunction statusColor(status: string): string {\n if (status === 'success') return SEMANTIC_COLORS.SUCCESS;\n if (status === 'fail' || status === 'error') return SEMANTIC_COLORS.DANGER;\n return SEMANTIC_COLORS.DEFAULT;\n}\n\nfunction categoryLabel(c?: string | null): string {\n if (c === 'TRACE') return '请求线路';\n if (c === 'SYSTEM') return '系统';\n if (c === 'OPERATION' || !c) return '业务操作';\n return c;\n}\n\nfunction httpStatusColor(code: number): string {\n if (code >= 500) return SEMANTIC_COLORS.DANGER;\n if (code >= 400) return SEMANTIC_COLORS.WARNING;\n if (code >= 200 && code < 300) return SEMANTIC_COLORS.SUCCESS;\n return SEMANTIC_COLORS.DEFAULT;\n}\n\nfunction parseHttpStatus(output: unknown): number | null {\n if (!output || typeof output !== 'object' || Array.isArray(output)) return null;\n const v = (output as { httpStatus?: unknown }).httpStatus;\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (v != null && String(v).trim() !== '') {\n const n = Number(v);\n return Number.isFinite(n) ? n : null;\n }\n return null;\n}\n\nfunction showActionCode(detail: AuditEventDetail): boolean {\n return Boolean(detail.actionLabel?.trim()) || Boolean(labelOfAction(detail.action));\n}\n\nconst JsonBlock: React.FC<{ value: unknown; maxHeight?: number }> = ({\n value,\n maxHeight = 360,\n}) => {\n const text = formatAuditJson(value);\n const truncated = isTruncatedAuditText(value) || text.includes('…[truncated]');\n return (\n <div className={styles.jsonWrap}>\n {truncated ? (\n <div className={styles.truncateHint}>内容已截断(采集侧 body 上限),以下为可读展开</div>\n ) : null}\n <VirtualScrollbar className={styles.jsonScroll} style={{ maxHeight }}>\n <pre className={styles.jsonBlock}>{text}</pre>\n </VirtualScrollbar>\n </div>\n );\n};\n\nfunction renderBody(label: string, value: unknown): React.ReactNode {\n if (value == null) return null;\n if (\n label === 'output' &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n value !== null &&\n ('httpStatus' in (value as object) || 'body' in (value as object))\n ) {\n const out = value as { body?: unknown; [k: string]: unknown };\n const rest = { ...out };\n delete rest.httpStatus;\n delete rest.body;\n const hasRest = Object.keys(rest).length > 0;\n return (\n <>\n {out.body !== undefined ? (\n <>\n <div className={styles.blockLabel}>响应体</div>\n <JsonBlock value={out.body} maxHeight={420} />\n </>\n ) : null}\n {hasRest ? (\n <>\n <div className={styles.blockLabel}>其它</div>\n <JsonBlock value={rest} />\n </>\n ) : null}\n </>\n );\n }\n return (\n <>\n <div className={styles.blockLabel}>{label}</div>\n <JsonBlock value={value} />\n </>\n );\n}\n\nexport const AuditStepContent: React.FC<{ step: AuditStep }> = ({ step }) => {\n const httpStatus = parseHttpStatus(step.output);\n return (\n <div className={styles.stepBody}>\n <div className={styles.stepMeta}>\n {step.stepType ? (\n <SemanticTag color={SEMANTIC_COLORS.DEFAULT}>{step.stepType}</SemanticTag>\n ) : null}\n {httpStatus != null ? (\n <SemanticTag color={httpStatusColor(httpStatus)}>HTTP {httpStatus}</SemanticTag>\n ) : null}\n {step.occurredAt ? (\n <Typography.Text type=\"secondary\">{formatCreatedAt(step.occurredAt)}</Typography.Text>\n ) : null}\n {typeof step.durationMs === 'number' ? (\n <Typography.Text type=\"secondary\">{step.durationMs} ms</Typography.Text>\n ) : null}\n </div>\n {step.sqlText ? (\n <>\n <div className={styles.blockLabel}>SQL</div>\n <VirtualScrollbar className={styles.jsonScroll} style={{ maxHeight: 200 }}>\n <pre className={styles.jsonBlock}>{step.sqlText}</pre>\n </VirtualScrollbar>\n </>\n ) : null}\n {step.tables?.length ? (\n <Typography.Text type=\"secondary\">表:{step.tables.join(', ')}</Typography.Text>\n ) : null}\n {step.errorMessage ? (\n <Typography.Text type=\"danger\">{step.errorMessage}</Typography.Text>\n ) : null}\n {step.errorCode ? (\n <Typography.Text type=\"secondary\">错误码:{step.errorCode}</Typography.Text>\n ) : null}\n {step.input != null ? renderBody('请求体', step.input) : null}\n {step.output != null ? renderBody('output', step.output) : null}\n </div>\n );\n};\n\n/** 审计事件详情:KPI + Lazy 瀑布 + 默认折叠 Flow */\nexport const AuditEventDetailView: React.FC<{\n detail: AuditEventDetail | null;\n loading?: boolean;\n emptyDescription?: string;\n className?: string;\n /** 当前登录 token(不含 Bearer 前缀亦可);复制 curl 用,不落库 */\n getAuthToken?: () => string | null | undefined;\n}> = ({ detail, loading, emptyDescription = '暂无明细', className, getAuthToken }) => {\n const kpi = useMemo(() => computeDetailKpi(detail), [detail]);\n const kpiItems = useMemo((): StatItem[] => {\n const slow =\n kpi.slowestStep != null ? `${kpi.slowestStep.title} (${kpi.slowestStep.durationMs}ms)` : '—';\n return [\n {\n title: '总耗时',\n value: kpi.durationMs ?? '—',\n suffix: kpi.durationMs != null ? 'ms' : undefined,\n tone: 'blue',\n color: '#1677ff',\n },\n { title: '步数', value: kpi.stepCount, tone: 'lilac', color: '#722ed1' },\n { title: 'SQL 步', value: kpi.sqlCount, tone: 'mint', color: '#0d9f8a' },\n { title: '最慢步', value: slow, tone: 'peach', color: '#d46b08' },\n ];\n }, [kpi]);\n\n if (loading) {\n return <Typography.Text type=\"secondary\">加载中…</Typography.Text>;\n }\n if (!detail) {\n return <Empty description={emptyDescription} />;\n }\n\n const steps = detail.steps || [];\n const title = displayActionLabel(detail.action, detail.actionLabel);\n const errorKeys = steps\n .map((s, i) => (isErrorStep(s) ? String(i) : null))\n .filter((k): k is string => k != null);\n\n const descContent = [\n {\n label: '操作人',\n value: detail.actorName?.trim() ? detail.actorName : '—',\n },\n { label: '时间', value: formatCreatedAt(detail.createdAt) },\n {\n label: '方法',\n value: detail.httpMethod?.trim() ? detail.httpMethod : '—',\n },\n {\n label: '状态',\n value: (\n <SemanticTag color={statusColor(detail.status)}>{statusLabel(detail.status)}</SemanticTag>\n ),\n },\n {\n label: '类别',\n value: detail.category ? categoryLabel(detail.category) : '—',\n },\n {\n label: '耗时',\n value: typeof detail.durationMs === 'number' ? `${detail.durationMs} ms` : '—',\n },\n {\n label: '路径',\n value: detail.path?.trim() ? (\n <Typography.Text code copyable={{ text: detail.path }}>\n {detail.path}\n </Typography.Text>\n ) : (\n '—'\n ),\n span: 2,\n },\n {\n label: 'traceId',\n value: detail.traceId ? (\n <Typography.Text copyable={{ text: detail.traceId }}>{detail.traceId}</Typography.Text>\n ) : (\n '—'\n ),\n span: 1,\n },\n ...(showActionCode(detail)\n ? [{ label: '动作码', value: <Typography.Text code>{detail.action}</Typography.Text> }]\n : []),\n ];\n\n return (\n <InfoPage className={classNames(styles.detail, className)}>\n <InfoPage.Part\n title={\n <Space size={8} wrap>\n <span>{title}</span>\n {title !== detail.action ? (\n <Typography.Text type=\"secondary\" className={styles.actionCode}>\n {detail.action}\n </Typography.Text>\n ) : null}\n </Space>\n }\n subtitle=\"事件摘要\"\n extra={\n detail.path || detail.requestCurl ? (\n <Button\n size=\"small\"\n type=\"primary\"\n onClick={async () => {\n try {\n const text = buildAuditReplayCurl(detail, readBrowserReplaySession(getAuthToken));\n const ok = await copyText(text);\n if (ok) message.success('已复制 curl');\n else message.error('复制失败');\n } catch (e) {\n message.error(e instanceof Error ? e.message : '无法生成 curl');\n }\n }}\n >\n 复制 curl\n </Button>\n ) : undefined\n }\n >\n <div className={styles.kpiBlock}>\n <StatCardList items={kpiItems} inline fontSize={20} gutter={[12, 8]} />\n </div>\n <CommonDescriptions content={descContent} column={3} bordered size=\"small\" />\n </InfoPage.Part>\n\n <InfoPage.Part title=\"耗时瀑布\" subtitle=\"逐步 durationMs(无 SQL 原文)\">\n <AuditWaterfall steps={steps} />\n </InfoPage.Part>\n\n <InfoPage.Part title=\"执行流程\" subtitle=\"默认折叠;失败步展开;展开后见 SQL/正文\">\n {detail.stepsTruncated ? (\n <div className={styles.truncateNote}>\n 步骤已截断:展示 {steps.length} / {detail.stepsTotal ?? steps.length}\n </div>\n ) : null}\n {steps.length === 0 ? (\n <Empty description=\"无流程步骤\" />\n ) : (\n <Collapse\n defaultActiveKey={errorKeys}\n items={steps.map((s, i) => ({\n key: String(i),\n label: (\n <Space size={8} wrap>\n <span>{s.title || s.stepType}</span>\n {typeof s.durationMs === 'number' ? (\n <Typography.Text type=\"secondary\">{s.durationMs} ms</Typography.Text>\n ) : null}\n {isErrorStep(s) ? (\n <SemanticTag color={SEMANTIC_COLORS.DANGER}>失败</SemanticTag>\n ) : null}\n </Space>\n ),\n children: <AuditStepContent step={s} />,\n }))}\n />\n )}\n </InfoPage.Part>\n </InfoPage>\n );\n};\n\nexport const AuditLogList: React.FC<AuditLogListProps> = ({\n mode = 'app',\n dataSource,\n loading,\n onRowClick,\n filterSlot,\n dayStats,\n dayStatsLoading,\n dayStatsError,\n onExport,\n exportLoading,\n pagination,\n className,\n systemAppNames,\n}) => {\n const columns: ColumnsType<AuditEventListItem> = useMemo(() => {\n const cols: ColumnsType<AuditEventListItem> = [\n {\n title: '时间',\n dataIndex: 'createdAt',\n width: 180,\n render: (v: string) => formatCreatedAt(v),\n },\n {\n title: '类别',\n dataIndex: 'category',\n width: 96,\n render: (v: string | undefined) => categoryLabel(v),\n },\n {\n title: '方法',\n dataIndex: 'httpMethod',\n width: 72,\n render: (v: string | null | undefined) => (v && String(v).trim() ? v : '—'),\n },\n {\n title: '操作人',\n dataIndex: 'actorName',\n width: 100,\n ellipsis: true,\n render: (v: string | null | undefined) => (v && String(v).trim() ? v : '—'),\n },\n {\n title: '动作',\n dataIndex: 'action',\n width: 160,\n ellipsis: true,\n render: (_: unknown, row) => displayActionLabel(row.action, row.actionLabel),\n },\n {\n title: '摘要',\n dataIndex: 'summary',\n ellipsis: true,\n render: (_: unknown, row) =>\n displaySummary(row.summary, displayActionLabel(row.action, row.actionLabel), {\n httpMethod: row.httpMethod,\n path: row.path,\n }),\n },\n {\n title: '状态',\n dataIndex: 'status',\n width: 90,\n render: (v: string) => <SemanticTag color={statusColor(v)}>{statusLabel(v)}</SemanticTag>,\n },\n { title: '耗时ms', dataIndex: 'durationMs', width: 80 },\n { title: '路径', dataIndex: 'path', ellipsis: true },\n ];\n if (mode === 'platform') {\n cols.splice(2, 0, {\n title: '系统',\n dataIndex: 'systemAppId',\n width: 140,\n ellipsis: true,\n render: (v: string) => {\n const id = v && String(v).trim() ? String(v) : '';\n if (!id) return '—';\n const name = systemAppNames?.[id]?.trim();\n return name || id;\n },\n });\n }\n return cols;\n }, [mode, systemAppNames]);\n\n return (\n <div className={classNames(styles.wrap, className)}>\n {filterSlot ? <div className={styles.filter}>{filterSlot}</div> : null}\n {dayStats !== undefined || onExport ? (\n <AuditDayStatsBar\n stats={dayStats ?? null}\n loading={dayStatsLoading}\n error={dayStatsError}\n onExport={onExport}\n exportLoading={exportLoading}\n />\n ) : null}\n <Table<AuditEventListItem>\n rowKey=\"id\"\n loading={loading}\n columns={columns}\n dataSource={dataSource}\n pagination={pagination === undefined ? false : pagination}\n onRow={\n onRowClick\n ? (record) => ({\n onClick: () => onRowClick(record),\n style: { cursor: 'pointer' },\n })\n : undefined\n }\n />\n </div>\n );\n};\n\nexport default AuditLogList;\n"],"names":["formatCreatedAt","iso","d","dayjs","statusLabel","status","statusColor","SEMANTIC_COLORS","categoryLabel","c","httpStatusColor","code","parseHttpStatus","output","v","n","showActionCode","detail","_a","labelOfAction","JsonBlock","value","maxHeight","text","formatAuditJson","truncated","isTruncatedAuditText","jsxs","styles","jsx","VirtualScrollbar","renderBody","label","out","rest","hasRest","Fragment","AuditStepContent","step","httpStatus","SemanticTag","Typography","AuditEventDetailView","loading","emptyDescription","className","getAuthToken","kpi","useMemo","computeDetailKpi","kpiItems","slow","Empty","steps","title","displayActionLabel","errorKeys","s","i","isErrorStep","k","descContent","_b","_c","InfoPage","classNames","Space","Button","buildAuditReplayCurl","readBrowserReplaySession","copyText","message","e","StatCardList","CommonDescriptions","AuditWaterfall","Collapse","AuditLogList","mode","dataSource","onRowClick","filterSlot","dayStats","dayStatsLoading","dayStatsError","onExport","exportLoading","pagination","systemAppNames","columns","cols","_","row","displaySummary","id","AuditDayStatsBar","Table","record"],"mappings":";;;;;;;;;;;;;;;;;;;AA0CA,SAASA,EAAgBC,GAAqB;AAC5C,QAAMC,IAAIC,EAAMF,CAAG;AACnB,SAAOC,EAAE,QAAA,IAAYA,EAAE,OAAO,qBAAqB,IAAID;AACzD;AAEA,SAASG,EAAYC,GAAwB;AAC3C,SAAIA,MAAW,YAAkB,OAC7BA,MAAW,UAAUA,MAAW,UAAgB,OAC7CA;AACT;AAEA,SAASC,EAAYD,GAAwB;AAC3C,SAAIA,MAAW,YAAkBE,EAAgB,UAC7CF,MAAW,UAAUA,MAAW,UAAgBE,EAAgB,SAC7DA,EAAgB;AACzB;AAEA,SAASC,EAAcC,GAA2B;AAChD,SAAIA,MAAM,UAAgB,SACtBA,MAAM,WAAiB,OACvBA,MAAM,eAAe,CAACA,IAAU,SAC7BA;AACT;AAEA,SAASC,GAAgBC,GAAsB;AAC7C,SAAIA,KAAQ,MAAYJ,EAAgB,SACpCI,KAAQ,MAAYJ,EAAgB,UACpCI,KAAQ,OAAOA,IAAO,MAAYJ,EAAgB,UAC/CA,EAAgB;AACzB;AAEA,SAASK,GAAgBC,GAAgC;AACvD,MAAI,CAACA,KAAU,OAAOA,KAAW,YAAY,MAAM,QAAQA,CAAM,EAAG,QAAO;AAC3E,QAAMC,IAAKD,EAAoC;AAC/C,MAAI,OAAOC,KAAM,YAAY,OAAO,SAASA,CAAC,EAAG,QAAOA;AACxD,MAAIA,KAAK,QAAQ,OAAOA,CAAC,EAAE,KAAA,MAAW,IAAI;AACxC,UAAMC,IAAI,OAAOD,CAAC;AAClB,WAAO,OAAO,SAASC,CAAC,IAAIA,IAAI;AAAA,EAClC;AACA,SAAO;AACT;AAEA,SAASC,GAAeC,GAAmC;;AACzD,SAAO,IAAQC,IAAAD,EAAO,gBAAP,QAAAC,EAAoB,WAAW,EAAQC,EAAcF,EAAO,MAAM;AACnF;AAEA,MAAMG,IAA8D,CAAC;AAAA,EACnE,OAAAC;AAAA,EACA,WAAAC,IAAY;AACd,MAAM;AACJ,QAAMC,IAAOC,EAAgBH,CAAK,GAC5BI,IAAYC,EAAqBL,CAAK,KAAKE,EAAK,SAAS,cAAc;AAC7E,SACE,gBAAAI,EAAC,OAAA,EAAI,WAAWC,EAAO,UACpB,UAAA;AAAA,IAAAH,sBACE,OAAA,EAAI,WAAWG,EAAO,cAAc,wCAA0B,IAC7D;AAAA,IACJ,gBAAAC,EAACC,GAAA,EAAiB,WAAWF,EAAO,YAAY,OAAO,EAAE,WAAAN,EAAA,GACvD,4BAAC,OAAA,EAAI,WAAWM,EAAO,WAAY,aAAK,EAAA,CAC1C;AAAA,EAAA,GACF;AAEJ;AAEA,SAASG,EAAWC,GAAeX,GAAiC;AAClE,MAAIA,KAAS,KAAM,QAAO;AAC1B,MACEW,MAAU,YACV,OAAOX,KAAU,YACjB,CAAC,MAAM,QAAQA,CAAK,KACpBA,MAAU,SACT,gBAAiBA,KAAoB,UAAWA,IACjD;AACA,UAAMY,IAAMZ,GACNa,IAAO,EAAE,GAAGD,EAAA;AAClB,WAAOC,EAAK,YACZ,OAAOA,EAAK;AACZ,UAAMC,IAAU,OAAO,KAAKD,CAAI,EAAE,SAAS;AAC3C,WACE,gBAAAP,EAAAS,GAAA,EACG,UAAA;AAAA,MAAAH,EAAI,SAAS,SACZ,gBAAAN,EAAAS,GAAA,EACE,UAAA;AAAA,QAAA,gBAAAP,EAAC,OAAA,EAAI,WAAWD,EAAO,YAAY,UAAA,OAAG;AAAA,0BACrCR,GAAA,EAAU,OAAOa,EAAI,MAAM,WAAW,IAAA,CAAK;AAAA,MAAA,EAAA,CAC9C,IACE;AAAA,MACHE,IACC,gBAAAR,EAAAS,GAAA,EACE,UAAA;AAAA,QAAA,gBAAAP,EAAC,OAAA,EAAI,WAAWD,EAAO,YAAY,UAAA,MAAE;AAAA,QACrC,gBAAAC,EAACT,GAAA,EAAU,OAAOc,EAAA,CAAM;AAAA,MAAA,EAAA,CAC1B,IACE;AAAA,IAAA,GACN;AAAA,EAEJ;AACA,SACE,gBAAAP,EAAAS,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAP,EAAC,OAAA,EAAI,WAAWD,EAAO,YAAa,UAAAI,GAAM;AAAA,IAC1C,gBAAAH,EAACT,KAAU,OAAAC,EAAA,CAAc;AAAA,EAAA,GAC3B;AAEJ;AAEO,MAAMgB,KAAkD,CAAC,EAAE,MAAAC,QAAW;;AAC3E,QAAMC,IAAa3B,GAAgB0B,EAAK,MAAM;AAC9C,SACE,gBAAAX,EAAC,OAAA,EAAI,WAAWC,EAAO,UACrB,UAAA;AAAA,IAAA,gBAAAD,EAAC,OAAA,EAAI,WAAWC,EAAO,UACpB,UAAA;AAAA,MAAAU,EAAK,6BACHE,GAAA,EAAY,OAAOjC,EAAgB,SAAU,UAAA+B,EAAK,UAAS,IAC1D;AAAA,MACHC,KAAc,OACb,gBAAAZ,EAACa,KAAY,OAAO9B,GAAgB6B,CAAU,GAAG,UAAA;AAAA,QAAA;AAAA,QAAMA;AAAA,MAAA,EAAA,CAAW,IAChE;AAAA,MACHD,EAAK,aACJ,gBAAAT,EAACY,EAAW,MAAX,EAAgB,MAAK,aAAa,UAAAzC,EAAgBsC,EAAK,UAAU,EAAA,CAAE,IAClE;AAAA,MACH,OAAOA,EAAK,cAAe,6BACzBG,EAAW,MAAX,EAAgB,MAAK,aAAa,UAAA;AAAA,QAAAH,EAAK;AAAA,QAAW;AAAA,MAAA,EAAA,CAAG,IACpD;AAAA,IAAA,GACN;AAAA,IACCA,EAAK,UACJ,gBAAAX,EAAAS,GAAA,EACE,UAAA;AAAA,MAAA,gBAAAP,EAAC,OAAA,EAAI,WAAWD,EAAO,YAAY,UAAA,OAAG;AAAA,wBACrCE,GAAA,EAAiB,WAAWF,EAAO,YAAY,OAAO,EAAE,WAAW,IAAA,GAClE,4BAAC,OAAA,EAAI,WAAWA,EAAO,WAAY,UAAAU,EAAK,SAAQ,EAAA,CAClD;AAAA,IAAA,EAAA,CACF,IACE;AAAA,KACHpB,IAAAoB,EAAK,WAAL,QAAApB,EAAa,SACZ,gBAAAS,EAACc,EAAW,MAAX,EAAgB,MAAK,aAAY,UAAA;AAAA,MAAA;AAAA,MAAGH,EAAK,OAAO,KAAK,IAAI;AAAA,IAAA,EAAA,CAAE,IAC1D;AAAA,IACHA,EAAK,eACJ,gBAAAT,EAACY,EAAW,MAAX,EAAgB,MAAK,UAAU,UAAAH,EAAK,aAAA,CAAa,IAChD;AAAA,IACHA,EAAK,YACJ,gBAAAX,EAACc,EAAW,MAAX,EAAgB,MAAK,aAAY,UAAA;AAAA,MAAA;AAAA,MAAKH,EAAK;AAAA,IAAA,EAAA,CAAU,IACpD;AAAA,IACHA,EAAK,SAAS,OAAOP,EAAW,OAAOO,EAAK,KAAK,IAAI;AAAA,IACrDA,EAAK,UAAU,OAAOP,EAAW,UAAUO,EAAK,MAAM,IAAI;AAAA,EAAA,GAC7D;AAEJ,GAGaI,KAOR,CAAC,EAAE,QAAAzB,GAAQ,SAAA0B,GAAS,kBAAAC,IAAmB,QAAQ,WAAAC,GAAW,cAAAC,QAAmB;;AAChF,QAAMC,IAAMC,EAAQ,MAAMC,EAAiBhC,CAAM,GAAG,CAACA,CAAM,CAAC,GACtDiC,IAAWF,EAAQ,MAAkB;AACzC,UAAMG,IACJJ,EAAI,eAAe,OAAO,GAAGA,EAAI,YAAY,KAAK,KAAKA,EAAI,YAAY,UAAU,QAAQ;AAC3F,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,OAAOA,EAAI,cAAc;AAAA,QACzB,QAAQA,EAAI,cAAc,OAAO,OAAO;AAAA,QACxC,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET,EAAE,OAAO,MAAM,OAAOA,EAAI,WAAW,MAAM,SAAS,OAAO,UAAA;AAAA,MAC3D,EAAE,OAAO,SAAS,OAAOA,EAAI,UAAU,MAAM,QAAQ,OAAO,UAAA;AAAA,MAC5D,EAAE,OAAO,OAAO,OAAOI,GAAM,MAAM,SAAS,OAAO,UAAA;AAAA,IAAU;AAAA,EAEjE,GAAG,CAACJ,CAAG,CAAC;AAER,MAAIJ;AACF,6BAAQF,EAAW,MAAX,EAAgB,MAAK,aAAY,UAAA,QAAI;AAE/C,MAAI,CAACxB;AACH,WAAO,gBAAAY,EAACuB,GAAA,EAAM,aAAaR,EAAA,CAAkB;AAG/C,QAAMS,IAAQpC,EAAO,SAAS,CAAA,GACxBqC,IAAQC,EAAmBtC,EAAO,QAAQA,EAAO,WAAW,GAC5DuC,IAAYH,EACf,IAAI,CAACI,GAAGC,MAAOC,EAAYF,CAAC,IAAI,OAAOC,CAAC,IAAI,IAAK,EACjD,OAAO,CAACE,MAAmBA,KAAK,IAAI,GAEjCC,IAAc;AAAA,IAClB;AAAA,MACE,OAAO;AAAA,MACP,QAAO3C,IAAAD,EAAO,cAAP,QAAAC,EAAkB,SAASD,EAAO,YAAY;AAAA,IAAA;AAAA,IAEvD,EAAE,OAAO,MAAM,OAAOjB,EAAgBiB,EAAO,SAAS,EAAA;AAAA,IACtD;AAAA,MACE,OAAO;AAAA,MACP,QAAO6C,IAAA7C,EAAO,eAAP,QAAA6C,EAAmB,SAAS7C,EAAO,aAAa;AAAA,IAAA;AAAA,IAEzD;AAAA,MACE,OAAO;AAAA,MACP,OACE,gBAAAY,EAACW,GAAA,EAAY,OAAOlC,EAAYW,EAAO,MAAM,GAAI,UAAAb,EAAYa,EAAO,MAAM,EAAA,CAAE;AAAA,IAAA;AAAA,IAGhF;AAAA,MACE,OAAO;AAAA,MACP,OAAOA,EAAO,WAAWT,EAAcS,EAAO,QAAQ,IAAI;AAAA,IAAA;AAAA,IAE5D;AAAA,MACE,OAAO;AAAA,MACP,OAAO,OAAOA,EAAO,cAAe,WAAW,GAAGA,EAAO,UAAU,QAAQ;AAAA,IAAA;AAAA,IAE7E;AAAA,MACE,OAAO;AAAA,MACP,QAAO8C,IAAA9C,EAAO,SAAP,QAAA8C,EAAa,SAClB,gBAAAlC,EAACY,EAAW,MAAX,EAAgB,MAAI,IAAC,UAAU,EAAE,MAAMxB,EAAO,QAC5C,UAAAA,EAAO,MACV,IAEA;AAAA,MAEF,MAAM;AAAA,IAAA;AAAA,IAER;AAAA,MACE,OAAO;AAAA,MACP,OAAOA,EAAO,UACZ,gBAAAY,EAACY,EAAW,MAAX,EAAgB,UAAU,EAAE,MAAMxB,EAAO,WAAY,UAAAA,EAAO,SAAQ,IAErE;AAAA,MAEF,MAAM;AAAA,IAAA;AAAA,IAER,GAAID,GAAeC,CAAM,IACrB,CAAC,EAAE,OAAO,OAAO,OAAO,gBAAAY,EAACY,EAAW,MAAX,EAAgB,MAAI,IAAE,UAAAxB,EAAO,QAAO,EAAA,CAAoB,IACjF,CAAA;AAAA,EAAC;AAGP,2BACG+C,GAAA,EAAS,WAAWC,EAAWrC,EAAO,QAAQiB,CAAS,GACtD,UAAA;AAAA,IAAA,gBAAAlB;AAAA,MAACqC,EAAS;AAAA,MAAT;AAAA,QACC,OACE,gBAAArC,EAACuC,GAAA,EAAM,MAAM,GAAG,MAAI,IAClB,UAAA;AAAA,UAAA,gBAAArC,EAAC,UAAM,UAAAyB,EAAA,CAAM;AAAA,UACZA,MAAUrC,EAAO,SAChB,gBAAAY,EAACY,EAAW,MAAX,EAAgB,MAAK,aAAY,WAAWb,EAAO,YACjD,UAAAX,EAAO,QACV,IACE;AAAA,QAAA,GACN;AAAA,QAEF,UAAS;AAAA,QACT,OACEA,EAAO,QAAQA,EAAO,cACpB,gBAAAY;AAAA,UAACsC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,SAAS,YAAY;AACnB,kBAAI;AACF,sBAAM5C,IAAO6C,EAAqBnD,GAAQoD,EAAyBvB,CAAY,CAAC;AAEhF,gBADW,MAAMwB,EAAS/C,CAAI,IACtBgD,EAAQ,QAAQ,UAAU,IAC7BA,EAAQ,MAAM,MAAM;AAAA,cAC3B,SAASC,GAAG;AACV,gBAAAD,EAAQ,MAAMC,aAAa,QAAQA,EAAE,UAAU,WAAW;AAAA,cAC5D;AAAA,YACF;AAAA,YACD,UAAA;AAAA,UAAA;AAAA,QAAA,IAGC;AAAA,QAGN,UAAA;AAAA,UAAA,gBAAA3C,EAAC,SAAI,WAAWD,EAAO,UACrB,UAAA,gBAAAC,EAAC4C,KAAa,OAAOvB,GAAU,QAAM,IAAC,UAAU,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,GACvE;AAAA,UACA,gBAAArB,EAAC6C,MAAmB,SAASb,GAAa,QAAQ,GAAG,UAAQ,IAAC,MAAK,QAAA,CAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAG7E,gBAAAhC,EAACmC,EAAS,MAAT,EAAc,OAAM,QAAO,UAAS,2BACnC,UAAA,gBAAAnC,EAAC8C,GAAA,EAAe,OAAAtB,EAAA,CAAc,EAAA,CAChC;AAAA,sBAECW,EAAS,MAAT,EAAc,OAAM,QAAO,UAAS,0BAClC,UAAA;AAAA,MAAA/C,EAAO,iBACN,gBAAAU,EAAC,OAAA,EAAI,WAAWC,EAAO,cAAc,UAAA;AAAA,QAAA;AAAA,QACzByB,EAAM;AAAA,QAAO;AAAA,QAAIpC,EAAO,cAAcoC,EAAM;AAAA,MAAA,EAAA,CACxD,IACE;AAAA,MACHA,EAAM,WAAW,sBACfD,GAAA,EAAM,aAAY,SAAQ,IAE3B,gBAAAvB;AAAA,QAAC+C;AAAA,QAAA;AAAA,UACC,kBAAkBpB;AAAA,UAClB,OAAOH,EAAM,IAAI,CAACI,GAAGC,OAAO;AAAA,YAC1B,KAAK,OAAOA,CAAC;AAAA,YACb,OACE,gBAAA/B,EAACuC,GAAA,EAAM,MAAM,GAAG,MAAI,IAClB,UAAA;AAAA,cAAA,gBAAArC,EAAC,QAAA,EAAM,UAAA4B,EAAE,SAASA,EAAE,UAAS;AAAA,cAC5B,OAAOA,EAAE,cAAe,6BACtBhB,EAAW,MAAX,EAAgB,MAAK,aAAa,UAAA;AAAA,gBAAAgB,EAAE;AAAA,gBAAW;AAAA,cAAA,EAAA,CAAG,IACjD;AAAA,cACHE,EAAYF,CAAC,IACZ,gBAAA5B,EAACW,KAAY,OAAOjC,EAAgB,QAAQ,UAAA,KAAA,CAAE,IAC5C;AAAA,YAAA,GACN;AAAA,YAEF,UAAU,gBAAAsB,EAACQ,IAAA,EAAiB,MAAMoB,EAAA,CAAG;AAAA,UAAA,EACrC;AAAA,QAAA;AAAA,MAAA;AAAA,IACJ,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ,GAEaoB,KAA4C,CAAC;AAAA,EACxD,MAAAC,IAAO;AAAA,EACP,YAAAC;AAAA,EACA,SAAApC;AAAA,EACA,YAAAqC;AAAA,EACA,YAAAC;AAAA,EACA,UAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,eAAAC;AAAA,EACA,UAAAC;AAAA,EACA,eAAAC;AAAA,EACA,YAAAC;AAAA,EACA,WAAA1C;AAAA,EACA,gBAAA2C;AACF,MAAM;AACJ,QAAMC,IAA2CzC,EAAQ,MAAM;AAC7D,UAAM0C,IAAwC;AAAA,MAC5C;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,OAAO;AAAA,QACP,QAAQ,CAAC5E,MAAcd,EAAgBc,CAAC;AAAA,MAAA;AAAA,MAE1C;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,OAAO;AAAA,QACP,QAAQ,CAACA,MAA0BN,EAAcM,CAAC;AAAA,MAAA;AAAA,MAEpD;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,OAAO;AAAA,QACP,QAAQ,CAACA,MAAkCA,KAAK,OAAOA,CAAC,EAAE,KAAA,IAASA,IAAI;AAAA,MAAA;AAAA,MAEzE;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,OAAO;AAAA,QACP,UAAU;AAAA,QACV,QAAQ,CAACA,MAAkCA,KAAK,OAAOA,CAAC,EAAE,KAAA,IAASA,IAAI;AAAA,MAAA;AAAA,MAEzE;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,OAAO;AAAA,QACP,UAAU;AAAA,QACV,QAAQ,CAAC6E,GAAYC,MAAQrC,EAAmBqC,EAAI,QAAQA,EAAI,WAAW;AAAA,MAAA;AAAA,MAE7E;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,UAAU;AAAA,QACV,QAAQ,CAACD,GAAYC,MACnBC,EAAeD,EAAI,SAASrC,EAAmBqC,EAAI,QAAQA,EAAI,WAAW,GAAG;AAAA,UAC3E,YAAYA,EAAI;AAAA,UAChB,MAAMA,EAAI;AAAA,QAAA,CACX;AAAA,MAAA;AAAA,MAEL;AAAA,QACE,OAAO;AAAA,QACP,WAAW;AAAA,QACX,OAAO;AAAA,QACP,QAAQ,CAAC9E,MAAc,gBAAAe,EAACW,GAAA,EAAY,OAAOlC,EAAYQ,CAAC,GAAI,UAAAV,EAAYU,CAAC,EAAA,CAAE;AAAA,MAAA;AAAA,MAE7E,EAAE,OAAO,QAAQ,WAAW,cAAc,OAAO,GAAA;AAAA,MACjD,EAAE,OAAO,MAAM,WAAW,QAAQ,UAAU,GAAA;AAAA,IAAK;AAEnD,WAAIgE,MAAS,cACXY,EAAK,OAAO,GAAG,GAAG;AAAA,MAChB,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO;AAAA,MACP,UAAU;AAAA,MACV,QAAQ,CAAC5E,MAAc;;AACrB,cAAMgF,IAAKhF,KAAK,OAAOA,CAAC,EAAE,SAAS,OAAOA,CAAC,IAAI;AAC/C,eAAKgF,MACQ5E,IAAAsE,KAAA,gBAAAA,EAAiBM,OAAjB,gBAAA5E,EAAsB,WACpB4E,IAFC;AAAA,MAGlB;AAAA,IAAA,CACD,GAEIJ;AAAA,EACT,GAAG,CAACZ,GAAMU,CAAc,CAAC;AAEzB,2BACG,OAAA,EAAI,WAAWvB,EAAWrC,EAAO,MAAMiB,CAAS,GAC9C,UAAA;AAAA,IAAAoC,sBAAc,OAAA,EAAI,WAAWrD,EAAO,QAAS,aAAW,IAAS;AAAA,IACjEsD,MAAa,UAAaG,IACzB,gBAAAxD;AAAA,MAACkE;AAAA,MAAA;AAAA,QACC,OAAOb,KAAY;AAAA,QACnB,SAASC;AAAA,QACT,OAAOC;AAAA,QACP,UAAAC;AAAA,QACA,eAAAC;AAAA,MAAA;AAAA,IAAA,IAEA;AAAA,IACJ,gBAAAzD;AAAA,MAACmE;AAAA,MAAA;AAAA,QACC,QAAO;AAAA,QACP,SAAArD;AAAA,QACA,SAAA8C;AAAA,QACA,YAAAV;AAAA,QACA,YAAYQ,MAAe,SAAY,KAAQA;AAAA,QAC/C,OACEP,IACI,CAACiB,OAAY;AAAA,UACX,SAAS,MAAMjB,EAAWiB,CAAM;AAAA,UAChC,OAAO,EAAE,QAAQ,UAAA;AAAA,QAAU,KAE7B;AAAA,MAAA;AAAA,IAAA;AAAA,EAER,GACF;AAEJ;"}
1
+ {"version":3,"file":"AuditLogList.js","sources":["../../../src/components/Audit/AuditLogList.tsx"],"sourcesContent":["import { CommonDescriptions } from '@/components/Descriptions';\nimport InfoPage from '@/components/InfoPage';\nimport { StatCardList, type StatItem } from '@/components/Stat';\nimport { Table } from '@/components/Table';\nimport { SEMANTIC_COLORS, SemanticTag } from '@/components/Tag';\nimport { VirtualScrollbar } from '@/components/VirtualScrollbar';\nimport { copyText } from '@/utils/copyText';\nimport { Button, Collapse, Empty, Space, Typography, message } from 'antd';\nimport type { ColumnsType } from 'antd/es/table';\nimport classNames from 'classnames';\nimport dayjs from 'dayjs';\nimport React, { useMemo } from 'react';\nimport { AuditDayStatsBar } from './AuditDayStatsBar';\nimport { AuditStepPerfChart } from './AuditStepPerfChart';\nimport { AuditWaterfall } from './AuditWaterfall';\nimport { computeDetailKpi, isErrorStep } from './detailKpi';\nimport { formatAuditJson, isTruncatedAuditText } from './formatAuditJson';\nimport { buildAuditReplayCurl, readBrowserReplaySession } from './formatAuditCurl';\nimport { displayActionLabel, displaySummary, labelOfAction } from './labels';\nimport styles from './style.module.scss';\nimport type { AuditDayStats, AuditEventDetail, AuditEventListItem, AuditStep } from './types';\n\nexport type AuditLogListMode = 'app' | 'platform';\n\nexport type AuditLogListProps = {\n mode?: AuditLogListMode;\n dataSource: AuditEventListItem[];\n loading?: boolean;\n /** 点击行(进详情页) */\n onRowClick?: (row: AuditEventListItem) => void;\n filterSlot?: React.ReactNode;\n /** 日汇总顶栏 */\n dayStats?: AuditDayStats | null;\n dayStatsLoading?: boolean;\n dayStatsError?: string | null;\n onExport?: () => void;\n exportLoading?: boolean;\n pagination?: false | object;\n className?: string;\n /** platform 系统列:SSO SystemApp.code → name;缺则回落 systemAppId */\n systemAppNames?: Record<string, string>;\n};\n\nfunction formatCreatedAt(iso: string): string {\n const d = dayjs(iso);\n return d.isValid() ? d.format('YYYY-MM-DD HH:mm:ss') : iso;\n}\n\nfunction statusLabel(status: string): string {\n if (status === 'success') return '成功';\n if (status === 'fail' || status === 'error') return '失败';\n return status;\n}\n\nfunction statusColor(status: string): string {\n if (status === 'success') return SEMANTIC_COLORS.SUCCESS;\n if (status === 'fail' || status === 'error') return SEMANTIC_COLORS.DANGER;\n return SEMANTIC_COLORS.DEFAULT;\n}\n\nfunction categoryLabel(c?: string | null): string {\n if (c === 'TRACE') return '请求线路';\n if (c === 'SYSTEM') return '系统';\n if (c === 'OPERATION' || !c) return '业务操作';\n return c;\n}\n\nfunction httpStatusColor(code: number): string {\n if (code >= 500) return SEMANTIC_COLORS.DANGER;\n if (code >= 400) return SEMANTIC_COLORS.WARNING;\n if (code >= 200 && code < 300) return SEMANTIC_COLORS.SUCCESS;\n return SEMANTIC_COLORS.DEFAULT;\n}\n\nfunction parseHttpStatus(output: unknown): number | null {\n if (!output || typeof output !== 'object' || Array.isArray(output)) return null;\n const v = (output as { httpStatus?: unknown }).httpStatus;\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (v != null && String(v).trim() !== '') {\n const n = Number(v);\n return Number.isFinite(n) ? n : null;\n }\n return null;\n}\n\nfunction showActionCode(detail: AuditEventDetail): boolean {\n return Boolean(detail.actionLabel?.trim()) || Boolean(labelOfAction(detail.action));\n}\n\nconst JsonBlock: React.FC<{ value: unknown; maxHeight?: number }> = ({\n value,\n maxHeight = 360,\n}) => {\n const text = formatAuditJson(value);\n const truncated = isTruncatedAuditText(value) || text.includes('…[truncated]');\n return (\n <div className={styles.jsonWrap}>\n {truncated ? (\n <div className={styles.truncateHint}>内容已截断(采集侧 body 上限),以下为可读展开</div>\n ) : null}\n <VirtualScrollbar className={styles.jsonScroll} style={{ maxHeight }}>\n <pre className={styles.jsonBlock}>{text}</pre>\n </VirtualScrollbar>\n </div>\n );\n};\n\nfunction renderBody(label: string, value: unknown): React.ReactNode {\n if (value == null) return null;\n if (\n label === 'output' &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n value !== null &&\n ('httpStatus' in (value as object) || 'body' in (value as object))\n ) {\n const out = value as { body?: unknown; [k: string]: unknown };\n const rest = { ...out };\n delete rest.httpStatus;\n delete rest.body;\n const hasRest = Object.keys(rest).length > 0;\n return (\n <>\n {out.body !== undefined ? (\n <>\n <div className={styles.blockLabel}>响应体</div>\n <JsonBlock value={out.body} maxHeight={420} />\n </>\n ) : null}\n {hasRest ? (\n <>\n <div className={styles.blockLabel}>其它</div>\n <JsonBlock value={rest} />\n </>\n ) : null}\n </>\n );\n }\n return (\n <>\n <div className={styles.blockLabel}>{label}</div>\n <JsonBlock value={value} />\n </>\n );\n}\n\nfunction stepTypeTagColor(stepType: string): string {\n const t = stepType.toUpperCase();\n if (t === 'SQL') return SEMANTIC_COLORS.CYAN;\n if (t === 'ERROR') return SEMANTIC_COLORS.DANGER;\n if (t === 'RESPONSE') return SEMANTIC_COLORS.SUCCESS;\n if (t === 'REQUEST') return SEMANTIC_COLORS.DEFAULT;\n if (t === 'AUTH' || t === 'UPSTREAM') return SEMANTIC_COLORS.WARNING;\n return SEMANTIC_COLORS.INFO;\n}\n\n/** Collapse header:类型 / HTTP / 耗时 / 表 / 失败 — 折叠态也可见 */\nexport const AuditStepHeader: React.FC<{ step: AuditStep }> = ({ step }) => {\n const httpStatus = parseHttpStatus(step.output);\n const tables = step.tables?.filter(Boolean) ?? [];\n return (\n <div className={styles.stepHeader}>\n <span className={styles.stepHeaderTitle}>{step.title || step.stepType}</span>\n {step.stepType ? (\n <SemanticTag color={stepTypeTagColor(String(step.stepType))}>{step.stepType}</SemanticTag>\n ) : null}\n {httpStatus != null ? (\n <SemanticTag color={httpStatusColor(httpStatus)}>HTTP {httpStatus}</SemanticTag>\n ) : null}\n {typeof step.durationMs === 'number' ? (\n <SemanticTag color={SEMANTIC_COLORS.DEFAULT}>{step.durationMs} ms</SemanticTag>\n ) : null}\n {tables.length > 0 ? (\n <SemanticTag color={SEMANTIC_COLORS.INFO}>表:{tables.join(', ')}</SemanticTag>\n ) : null}\n {step.sqlText && String(step.stepType).toUpperCase() !== 'SQL' ? (\n <SemanticTag color={SEMANTIC_COLORS.CYAN}>SQL</SemanticTag>\n ) : null}\n {isErrorStep(step) ? <SemanticTag color={SEMANTIC_COLORS.DANGER}>失败</SemanticTag> : null}\n </div>\n );\n};\n\nexport const AuditStepContent: React.FC<{ step: AuditStep }> = ({ step }) => {\n return (\n <div className={styles.stepBody}>\n {step.occurredAt ? (\n <Typography.Text type=\"secondary\">{formatCreatedAt(step.occurredAt)}</Typography.Text>\n ) : null}\n {step.sqlText ? (\n <>\n <div className={styles.blockLabel}>SQL</div>\n <VirtualScrollbar className={styles.jsonScroll} style={{ maxHeight: 200 }}>\n <pre className={styles.jsonBlock}>{step.sqlText}</pre>\n </VirtualScrollbar>\n </>\n ) : null}\n {step.errorMessage ? (\n <Typography.Text type=\"danger\">{step.errorMessage}</Typography.Text>\n ) : null}\n {step.errorCode ? (\n <Typography.Text type=\"secondary\">错误码:{step.errorCode}</Typography.Text>\n ) : null}\n {step.input != null ? renderBody('请求体', step.input) : null}\n {step.output != null ? renderBody('output', step.output) : null}\n </div>\n );\n};\n\n/** 审计事件详情:KPI + Lazy 瀑布 + 默认折叠 Flow */\nexport const AuditEventDetailView: React.FC<{\n detail: AuditEventDetail | null;\n loading?: boolean;\n emptyDescription?: string;\n className?: string;\n /** 当前登录 token(不含 Bearer 前缀亦可);复制 curl 用,不落库 */\n getAuthToken?: () => string | null | undefined;\n}> = ({ detail, loading, emptyDescription = '暂无明细', className, getAuthToken }) => {\n const kpi = useMemo(() => computeDetailKpi(detail), [detail]);\n const kpiItems = useMemo((): StatItem[] => {\n const slow =\n kpi.slowestStep != null ? `${kpi.slowestStep.title} (${kpi.slowestStep.durationMs}ms)` : '—';\n return [\n {\n title: '总耗时',\n value: kpi.durationMs ?? '—',\n suffix: kpi.durationMs != null ? 'ms' : undefined,\n tone: 'blue',\n color: '#1677ff',\n },\n { title: '步数', value: kpi.stepCount, tone: 'lilac', color: '#722ed1' },\n { title: 'SQL 步', value: kpi.sqlCount, tone: 'mint', color: '#0d9f8a' },\n { title: '最慢步', value: slow, tone: 'peach', color: '#d46b08' },\n ];\n }, [kpi]);\n\n if (loading) {\n return <Typography.Text type=\"secondary\">加载中…</Typography.Text>;\n }\n if (!detail) {\n return <Empty description={emptyDescription} />;\n }\n\n const steps = detail.steps || [];\n const title = displayActionLabel(detail.action, detail.actionLabel);\n const errorKeys = steps\n .map((s, i) => (isErrorStep(s) ? String(i) : null))\n .filter((k): k is string => k != null);\n\n const descContent = [\n {\n label: '操作人',\n value: detail.actorName?.trim() ? detail.actorName : '—',\n },\n { label: '时间', value: formatCreatedAt(detail.createdAt) },\n {\n label: '方法',\n value: detail.httpMethod?.trim() ? detail.httpMethod : '—',\n },\n {\n label: '状态',\n value: (\n <SemanticTag color={statusColor(detail.status)}>{statusLabel(detail.status)}</SemanticTag>\n ),\n },\n {\n label: '类别',\n value: detail.category ? categoryLabel(detail.category) : '—',\n },\n {\n label: '耗时',\n value: typeof detail.durationMs === 'number' ? `${detail.durationMs} ms` : '—',\n },\n {\n label: '路径',\n value: detail.path?.trim() ? (\n <Typography.Text code copyable={{ text: detail.path }}>\n {detail.path}\n </Typography.Text>\n ) : (\n '—'\n ),\n span: 2,\n },\n {\n label: 'traceId',\n value: detail.traceId ? (\n <Typography.Text copyable={{ text: detail.traceId }}>{detail.traceId}</Typography.Text>\n ) : (\n '—'\n ),\n span: 1,\n },\n ...(showActionCode(detail)\n ? [{ label: '动作码', value: <Typography.Text code>{detail.action}</Typography.Text> }]\n : []),\n ];\n\n return (\n <InfoPage className={classNames(styles.detail, className)}>\n <InfoPage.Part\n title={\n <Space size={8} wrap>\n <span>{title}</span>\n {title !== detail.action ? (\n <Typography.Text type=\"secondary\" className={styles.actionCode}>\n {detail.action}\n </Typography.Text>\n ) : null}\n </Space>\n }\n subtitle=\"事件摘要\"\n extra={\n detail.path || detail.requestCurl ? (\n <Button\n size=\"small\"\n type=\"primary\"\n onClick={async () => {\n try {\n const text = buildAuditReplayCurl(detail, readBrowserReplaySession(getAuthToken));\n const ok = await copyText(text);\n if (ok) message.success('已复制 curl');\n else message.error('复制失败');\n } catch (e) {\n message.error(e instanceof Error ? e.message : '无法生成 curl');\n }\n }}\n >\n 复制 curl\n </Button>\n ) : undefined\n }\n >\n <div className={styles.kpiBlock}>\n <StatCardList items={kpiItems} inline fontSize={20} gutter={[12, 8]} />\n </div>\n <CommonDescriptions content={descContent} column={3} bordered size=\"small\" />\n </InfoPage.Part>\n\n <InfoPage.Part title=\"耗时瀑布\">\n <AuditWaterfall steps={steps} />\n </InfoPage.Part>\n\n <InfoPage.Part title=\"性能分析\">\n <AuditStepPerfChart steps={steps} />\n </InfoPage.Part>\n\n <InfoPage.Part title=\"执行流程\">\n {detail.stepsTruncated ? (\n <div className={styles.truncateNote}>\n 步骤已截断:展示 {steps.length} / {detail.stepsTotal ?? steps.length}\n </div>\n ) : null}\n {steps.length === 0 ? (\n <Empty description=\"无流程步骤\" />\n ) : (\n <Collapse\n defaultActiveKey={errorKeys}\n items={steps.map((s, i) => ({\n key: String(i),\n label: <AuditStepHeader step={s} />,\n children: <AuditStepContent step={s} />,\n }))}\n />\n )}\n </InfoPage.Part>\n </InfoPage>\n );\n};\n\nexport const AuditLogList: React.FC<AuditLogListProps> = ({\n mode = 'app',\n dataSource,\n loading,\n onRowClick,\n filterSlot,\n dayStats,\n dayStatsLoading,\n dayStatsError,\n onExport,\n exportLoading,\n pagination,\n className,\n systemAppNames,\n}) => {\n const columns: ColumnsType<AuditEventListItem> = useMemo(() => {\n const cols: ColumnsType<AuditEventListItem> = [\n {\n title: '时间',\n dataIndex: 'createdAt',\n width: 180,\n render: (v: string) => formatCreatedAt(v),\n },\n {\n title: '类别',\n dataIndex: 'category',\n width: 96,\n render: (v: string | undefined) => categoryLabel(v),\n },\n {\n title: '方法',\n dataIndex: 'httpMethod',\n width: 72,\n render: (v: string | null | undefined) => (v && String(v).trim() ? v : '—'),\n },\n {\n title: '操作人',\n dataIndex: 'actorName',\n width: 100,\n ellipsis: true,\n render: (v: string | null | undefined) => (v && String(v).trim() ? v : '—'),\n },\n {\n title: '动作',\n dataIndex: 'action',\n width: 160,\n ellipsis: true,\n render: (_: unknown, row) => displayActionLabel(row.action, row.actionLabel),\n },\n {\n title: '摘要',\n dataIndex: 'summary',\n ellipsis: true,\n render: (_: unknown, row) =>\n displaySummary(row.summary, displayActionLabel(row.action, row.actionLabel), {\n httpMethod: row.httpMethod,\n path: row.path,\n }),\n },\n {\n title: '状态',\n dataIndex: 'status',\n width: 90,\n render: (v: string) => <SemanticTag color={statusColor(v)}>{statusLabel(v)}</SemanticTag>,\n },\n { title: '耗时ms', dataIndex: 'durationMs', width: 80 },\n { title: '路径', dataIndex: 'path', ellipsis: true },\n ];\n if (mode === 'platform') {\n cols.splice(2, 0, {\n title: '系统',\n dataIndex: 'systemAppId',\n width: 140,\n ellipsis: true,\n render: (v: string) => {\n const id = v && String(v).trim() ? String(v) : '';\n if (!id) return '—';\n const name = systemAppNames?.[id]?.trim();\n return name || id;\n },\n });\n }\n return cols;\n }, [mode, systemAppNames]);\n\n return (\n <div className={classNames(styles.wrap, className)}>\n {filterSlot ? <div className={styles.filter}>{filterSlot}</div> : null}\n {dayStats !== undefined || onExport ? (\n <AuditDayStatsBar\n stats={dayStats ?? null}\n loading={dayStatsLoading}\n error={dayStatsError}\n onExport={onExport}\n exportLoading={exportLoading}\n />\n ) : null}\n <Table<AuditEventListItem>\n rowKey=\"id\"\n loading={loading}\n columns={columns}\n dataSource={dataSource}\n pagination={pagination === undefined ? false : pagination}\n onRow={\n onRowClick\n ? (record) => ({\n onClick: () => onRowClick(record),\n style: { cursor: 'pointer' },\n })\n : undefined\n }\n />\n </div>\n );\n};\n\nexport default AuditLogList;\n"],"names":["formatCreatedAt","iso","d","dayjs","statusLabel","status","statusColor","SEMANTIC_COLORS","categoryLabel","c","httpStatusColor","code","parseHttpStatus","output","v","n","showActionCode","detail","_a","labelOfAction","JsonBlock","value","maxHeight","text","formatAuditJson","truncated","isTruncatedAuditText","jsxs","styles","jsx","VirtualScrollbar","renderBody","label","out","rest","hasRest","Fragment","stepTypeTagColor","stepType","t","AuditStepHeader","step","httpStatus","tables","SemanticTag","isErrorStep","AuditStepContent","Typography","AuditEventDetailView","loading","emptyDescription","className","getAuthToken","kpi","useMemo","computeDetailKpi","kpiItems","slow","Empty","steps","title","displayActionLabel","errorKeys","s","i","k","descContent","_b","_c","InfoPage","classNames","Space","Button","buildAuditReplayCurl","readBrowserReplaySession","copyText","message","e","StatCardList","CommonDescriptions","AuditWaterfall","AuditStepPerfChart","Collapse","AuditLogList","mode","dataSource","onRowClick","filterSlot","dayStats","dayStatsLoading","dayStatsError","onExport","exportLoading","pagination","systemAppNames","columns","cols","_","row","displaySummary","id","AuditDayStatsBar","Table","record"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ import { AuditStep } from './types';
3
+ export type AuditStepPerfChartProps = {
4
+ steps: AuditStep[];
5
+ height?: number;
6
+ className?: string;
7
+ };
8
+ /** 单事件逐步耗时占比(饼图);无 durationMs → Empty */
9
+ export declare const AuditStepPerfChart: React.FC<AuditStepPerfChartProps>;
10
+ export default AuditStepPerfChart;
@@ -0,0 +1,51 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { Empty as n, Typography as l } from "antd";
3
+ import { useMemo as s } from "react";
4
+ import { LazyPie as m } from "./Chart/createLazyPlot.js";
5
+ import { waterfallChartData as p } from "./detailKpi.js";
6
+ const h = ({
7
+ steps: o,
8
+ height: i = 340,
9
+ className: a
10
+ }) => {
11
+ const r = s(() => p(o), [o]);
12
+ return r.length === 0 ? /* @__PURE__ */ e(
13
+ n,
14
+ {
15
+ description: /* @__PURE__ */ e(l.Text, { type: "secondary", children: "无逐步耗时(旧事件未采集 durationMs,不伪造)" })
16
+ }
17
+ ) : /* @__PURE__ */ e("div", { className: a, children: /* @__PURE__ */ e(
18
+ m,
19
+ {
20
+ height: i,
21
+ data: r,
22
+ angleField: "durationMs",
23
+ colorField: "title",
24
+ radius: 0.72,
25
+ legend: {
26
+ color: {
27
+ position: "bottom",
28
+ layout: { justifyContent: "center", flexWrap: "wrap" }
29
+ }
30
+ },
31
+ label: {
32
+ text: (t) => `${t.durationMs ?? 0}ms`,
33
+ position: "outside",
34
+ style: { fontSize: 11 },
35
+ transform: [{ type: "overlapHide" }]
36
+ },
37
+ tooltip: {
38
+ title: (t) => (t == null ? void 0 : t.title) ?? "",
39
+ items: [{ field: "durationMs", name: "耗时(ms)" }]
40
+ },
41
+ interaction: {
42
+ tooltip: { shared: !1 },
43
+ elementHighlight: { background: !0 }
44
+ }
45
+ }
46
+ ) });
47
+ };
48
+ export {
49
+ h as AuditStepPerfChart
50
+ };
51
+ //# sourceMappingURL=AuditStepPerfChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuditStepPerfChart.js","sources":["../../../src/components/Audit/AuditStepPerfChart.tsx"],"sourcesContent":["import { Empty, Typography } from 'antd';\nimport React, { useMemo } from 'react';\nimport { LazyPie } from './Chart/createLazyPlot';\nimport { waterfallChartData } from './detailKpi';\nimport type { AuditStep } from './types';\n\nexport type AuditStepPerfChartProps = {\n steps: AuditStep[];\n height?: number;\n className?: string;\n};\n\n/** 单事件逐步耗时占比(饼图);无 durationMs → Empty */\nexport const AuditStepPerfChart: React.FC<AuditStepPerfChartProps> = ({\n steps,\n height = 340,\n className,\n}) => {\n const data = useMemo(() => waterfallChartData(steps), [steps]);\n\n if (data.length === 0) {\n return (\n <Empty\n description={\n <Typography.Text type=\"secondary\">\n 无逐步耗时(旧事件未采集 durationMs,不伪造)\n </Typography.Text>\n }\n />\n );\n }\n\n return (\n <div className={className}>\n <LazyPie\n height={height}\n data={data}\n angleField=\"durationMs\"\n colorField=\"title\"\n radius={0.72}\n // G2/plots v2:按通道配 legend;bottom 避免与 outside 标签叠在顶部\n legend={{\n color: {\n position: 'bottom',\n layout: { justifyContent: 'center', flexWrap: 'wrap' },\n },\n }}\n // 扇区只标耗时;步骤名留给底部 legend,避免长文案顶到图例\n label={{\n text: (d: { durationMs?: number }) => `${d.durationMs ?? 0}ms`,\n position: 'outside',\n style: { fontSize: 11 },\n transform: [{ type: 'overlapHide' }],\n }}\n tooltip={{\n title: (d: { title?: string }) => d?.title ?? '',\n items: [{ field: 'durationMs', name: '耗时(ms)' }],\n }}\n interaction={{\n tooltip: { shared: false },\n elementHighlight: { background: true },\n }}\n />\n </div>\n );\n};\n\nexport default AuditStepPerfChart;\n"],"names":["AuditStepPerfChart","steps","height","className","data","useMemo","waterfallChartData","jsx","Empty","Typography","LazyPie","d"],"mappings":";;;;;AAaO,MAAMA,IAAwD,CAAC;AAAA,EACpE,OAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,WAAAC;AACF,MAAM;AACJ,QAAMC,IAAOC,EAAQ,MAAMC,EAAmBL,CAAK,GAAG,CAACA,CAAK,CAAC;AAE7D,SAAIG,EAAK,WAAW,IAEhB,gBAAAG;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,aACE,gBAAAD,EAACE,EAAW,MAAX,EAAgB,MAAK,aAAY,UAAA,+BAAA,CAElC;AAAA,IAAA;AAAA,EAAA,IAON,gBAAAF,EAAC,SAAI,WAAAJ,GACH,UAAA,gBAAAI;AAAA,IAACG;AAAA,IAAA;AAAA,MACC,QAAAR;AAAA,MACA,MAAAE;AAAA,MACA,YAAW;AAAA,MACX,YAAW;AAAA,MACX,QAAQ;AAAA,MAER,QAAQ;AAAA,QACN,OAAO;AAAA,UACL,UAAU;AAAA,UACV,QAAQ,EAAE,gBAAgB,UAAU,UAAU,OAAA;AAAA,QAAO;AAAA,MACvD;AAAA,MAGF,OAAO;AAAA,QACL,MAAM,CAACO,MAA+B,GAAGA,EAAE,cAAc,CAAC;AAAA,QAC1D,UAAU;AAAA,QACV,OAAO,EAAE,UAAU,GAAA;AAAA,QACnB,WAAW,CAAC,EAAE,MAAM,eAAe;AAAA,MAAA;AAAA,MAErC,SAAS;AAAA,QACP,OAAO,CAACA,OAA0BA,KAAA,gBAAAA,EAAG,UAAS;AAAA,QAC9C,OAAO,CAAC,EAAE,OAAO,cAAc,MAAM,UAAU;AAAA,MAAA;AAAA,MAEjD,aAAa;AAAA,QACX,SAAS,EAAE,QAAQ,GAAA;AAAA,QACnB,kBAAkB,EAAE,YAAY,GAAA;AAAA,MAAK;AAAA,IACvC;AAAA,EAAA,GAEJ;AAEJ;"}
@@ -2,9 +2,13 @@ import { default as React } from 'react';
2
2
  import { AuditStep } from './types';
3
3
  export type AuditWaterfallProps = {
4
4
  steps: AuditStep[];
5
+ /** 保留兼容;CSS 时序条按内容自适应,不再依赖 canvas 定高 */
5
6
  height?: number;
6
7
  className?: string;
7
8
  };
8
- /** 逐步耗时横向 Bar;无耗时 → Empty 诚实 */
9
+ /**
10
+ * DevTools Timing 风格:左标签 | 中区间条 | 右耗时。
11
+ * 文案在条外,避免短条白字压底;CSS 条(非自研 SVG 业务图)。
12
+ */
9
13
  export declare const AuditWaterfall: React.FC<AuditWaterfallProps>;
10
14
  export default AuditWaterfall;
@@ -1,39 +1,55 @@
1
- import { jsx as t } from "react/jsx-runtime";
2
- import { Empty as l, Typography as m } from "antd";
3
- import { useMemo as d } from "react";
4
- import { LazyBar as n } from "./Chart/createLazyPlot.js";
5
- import { waterfallChartData as s } from "./detailKpi.js";
6
- const x = ({
7
- steps: e,
8
- height: i = 280,
9
- className: o
10
- }) => {
11
- const r = d(() => s(e), [e]);
12
- return r.length === 0 ? /* @__PURE__ */ t(
13
- l,
14
- {
15
- description: /* @__PURE__ */ t(m.Text, { type: "secondary", children: "无逐步耗时(旧事件未采集 durationMs,不伪造)" })
16
- }
17
- ) : /* @__PURE__ */ t("div", { className: o, children: /* @__PURE__ */ t(
18
- n,
19
- {
20
- height: i,
21
- data: r,
22
- xField: "durationMs",
23
- yField: "title",
24
- legend: !1,
25
- axis: {
26
- x: { title: "ms" },
27
- y: { title: !1 }
28
- },
29
- tooltip: {
30
- title: (a) => a.title,
31
- items: [{ field: "durationMs", name: "耗时(ms)" }]
1
+ import { jsx as e, jsxs as s } from "react/jsx-runtime";
2
+ import { Empty as u, Typography as m } from "antd";
3
+ import d from "classnames";
4
+ import { useMemo as p } from "react";
5
+ import { waterfallChartData as g } from "./detailKpi.js";
6
+ import r from "./style.module.scss.js";
7
+ function v(n) {
8
+ const i = n.toUpperCase();
9
+ return i === "SQL" ? "var(--success-color, #52c41a)" : i === "RESPONSE" ? "var(--primary-color, #1677ff)" : i === "ERROR" ? "var(--error-color, #ff4d4f)" : i === "AUTH" || i === "UPSTREAM" ? "var(--warning-color, #fa8c16)" : i === "TRANSFORM" ? "#13c2c2" : "#595959";
10
+ }
11
+ const E = ({ steps: n, className: i }) => {
12
+ const a = p(() => g(n), [n]), c = a.length > 0 ? a[a.length - 1].endMs : 0;
13
+ if (a.length === 0)
14
+ return /* @__PURE__ */ e(
15
+ u,
16
+ {
17
+ description: /* @__PURE__ */ e(m.Text, { type: "secondary", children: "无逐步耗时(旧事件未采集 durationMs,不伪造)" })
32
18
  }
33
- }
34
- ) });
19
+ );
20
+ const o = c > 0 ? c : 1;
21
+ return /* @__PURE__ */ s("div", { className: d(r.timing, i), children: [
22
+ /* @__PURE__ */ e("div", { className: r.timingRows, children: a.map((t) => {
23
+ const f = t.startMs / o * 100, h = Math.max(t.durationMs / o * 100, 0.35), l = t.durationMs / o < 0.02;
24
+ return /* @__PURE__ */ s("div", { className: r.timingRow, children: [
25
+ /* @__PURE__ */ e("div", { className: r.timingLabel, title: t.title, children: t.title }),
26
+ /* @__PURE__ */ e("div", { className: r.timingTrack, "aria-hidden": !0, children: /* @__PURE__ */ e(
27
+ "div",
28
+ {
29
+ className: d(r.timingBar, l && r.timingBarThin),
30
+ style: {
31
+ left: `${f}%`,
32
+ width: l ? void 0 : `${h}%`,
33
+ background: v(t.stepType)
34
+ }
35
+ }
36
+ ) }),
37
+ /* @__PURE__ */ s("div", { className: r.timingMs, children: [
38
+ t.durationMs,
39
+ " ms"
40
+ ] })
41
+ ] }, `${t.title}-${t.startMs}`);
42
+ }) }),
43
+ /* @__PURE__ */ s("div", { className: r.timingFoot, children: [
44
+ /* @__PURE__ */ e("span", {}),
45
+ /* @__PURE__ */ s(m.Text, { strong: !0, children: [
46
+ c,
47
+ " ms"
48
+ ] })
49
+ ] })
50
+ ] });
35
51
  };
36
52
  export {
37
- x as AuditWaterfall
53
+ E as AuditWaterfall
38
54
  };
39
55
  //# sourceMappingURL=AuditWaterfall.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuditWaterfall.js","sources":["../../../src/components/Audit/AuditWaterfall.tsx"],"sourcesContent":["import { Empty, Typography } from 'antd';\nimport React, { useMemo } from 'react';\nimport { LazyBar } from './Chart/createLazyPlot';\nimport { waterfallChartData } from './detailKpi';\nimport type { AuditStep } from './types';\n\nexport type AuditWaterfallProps = {\n steps: AuditStep[];\n height?: number;\n className?: string;\n};\n\n/** 逐步耗时横向 Bar;无耗时 → Empty 诚实 */\nexport const AuditWaterfall: React.FC<AuditWaterfallProps> = ({\n steps,\n height = 280,\n className,\n}) => {\n const data = useMemo(() => waterfallChartData(steps), [steps]);\n\n if (data.length === 0) {\n return (\n <Empty\n description={\n <Typography.Text type=\"secondary\">\n 无逐步耗时(旧事件未采集 durationMs,不伪造)\n </Typography.Text>\n }\n />\n );\n }\n\n return (\n <div className={className}>\n <LazyBar\n height={height}\n data={data}\n xField=\"durationMs\"\n yField=\"title\"\n legend={false}\n axis={{\n x: { title: 'ms' },\n y: { title: false },\n }}\n tooltip={{\n title: (d: { title?: string }) => d.title,\n items: [{ field: 'durationMs', name: '耗时(ms)' }],\n }}\n />\n </div>\n );\n};\n\nexport default AuditWaterfall;\n"],"names":["AuditWaterfall","steps","height","className","data","useMemo","waterfallChartData","jsx","Empty","Typography","LazyBar","d"],"mappings":";;;;;AAaO,MAAMA,IAAgD,CAAC;AAAA,EAC5D,OAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,WAAAC;AACF,MAAM;AACJ,QAAMC,IAAOC,EAAQ,MAAMC,EAAmBL,CAAK,GAAG,CAACA,CAAK,CAAC;AAE7D,SAAIG,EAAK,WAAW,IAEhB,gBAAAG;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,aACE,gBAAAD,EAACE,EAAW,MAAX,EAAgB,MAAK,aAAY,UAAA,+BAAA,CAElC;AAAA,IAAA;AAAA,EAAA,IAON,gBAAAF,EAAC,SAAI,WAAAJ,GACH,UAAA,gBAAAI;AAAA,IAACG;AAAA,IAAA;AAAA,MACC,QAAAR;AAAA,MACA,MAAAE;AAAA,MACA,QAAO;AAAA,MACP,QAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,GAAG,EAAE,OAAO,KAAA;AAAA,QACZ,GAAG,EAAE,OAAO,GAAA;AAAA,MAAM;AAAA,MAEpB,SAAS;AAAA,QACP,OAAO,CAACO,MAA0BA,EAAE;AAAA,QACpC,OAAO,CAAC,EAAE,OAAO,cAAc,MAAM,UAAU;AAAA,MAAA;AAAA,IACjD;AAAA,EAAA,GAEJ;AAEJ;"}
1
+ {"version":3,"file":"AuditWaterfall.js","sources":["../../../src/components/Audit/AuditWaterfall.tsx"],"sourcesContent":["import { Empty, Typography } from 'antd';\nimport classNames from 'classnames';\nimport React, { useMemo } from 'react';\nimport { waterfallChartData } from './detailKpi';\nimport styles from './style.module.scss';\nimport type { AuditStep } from './types';\n\nexport type AuditWaterfallProps = {\n steps: AuditStep[];\n /** 保留兼容;CSS 时序条按内容自适应,不再依赖 canvas 定高 */\n height?: number;\n className?: string;\n};\n\nfunction barColor(stepType: string): string {\n const t = stepType.toUpperCase();\n if (t === 'SQL') return 'var(--success-color, #52c41a)';\n if (t === 'RESPONSE') return 'var(--primary-color, #1677ff)';\n if (t === 'ERROR') return 'var(--error-color, #ff4d4f)';\n if (t === 'AUTH' || t === 'UPSTREAM') return 'var(--warning-color, #fa8c16)';\n if (t === 'TRANSFORM') return '#13c2c2';\n return '#595959';\n}\n\n/**\n * DevTools Timing 风格:左标签 | 中区间条 | 右耗时。\n * 文案在条外,避免短条白字压底;CSS 条(非自研 SVG 业务图)。\n */\nexport const AuditWaterfall: React.FC<AuditWaterfallProps> = ({ steps, className }) => {\n const data = useMemo(() => waterfallChartData(steps), [steps]);\n const totalMs = data.length > 0 ? data[data.length - 1]!.endMs : 0;\n\n if (data.length === 0) {\n return (\n <Empty\n description={\n <Typography.Text type=\"secondary\">\n 无逐步耗时(旧事件未采集 durationMs,不伪造)\n </Typography.Text>\n }\n />\n );\n }\n\n const scale = totalMs > 0 ? totalMs : 1;\n\n return (\n <div className={classNames(styles.timing, className)}>\n <div className={styles.timingRows}>\n {data.map((row) => {\n const leftPct = (row.startMs / scale) * 100;\n const widthPct = Math.max((row.durationMs / scale) * 100, 0.35);\n const thin = row.durationMs / scale < 0.02;\n return (\n <div key={`${row.title}-${row.startMs}`} className={styles.timingRow}>\n <div className={styles.timingLabel} title={row.title}>\n {row.title}\n </div>\n <div className={styles.timingTrack} aria-hidden>\n <div\n className={classNames(styles.timingBar, thin && styles.timingBarThin)}\n style={{\n left: `${leftPct}%`,\n width: thin ? undefined : `${widthPct}%`,\n background: barColor(row.stepType),\n }}\n />\n </div>\n <div className={styles.timingMs}>{row.durationMs} ms</div>\n </div>\n );\n })}\n </div>\n <div className={styles.timingFoot}>\n <span />\n <Typography.Text strong>{totalMs} ms</Typography.Text>\n </div>\n </div>\n );\n};\n\nexport default AuditWaterfall;\n"],"names":["barColor","stepType","t","AuditWaterfall","steps","className","data","useMemo","waterfallChartData","totalMs","jsx","Empty","Typography","scale","classNames","styles","row","leftPct","widthPct","thin","jsxs"],"mappings":";;;;;;AAcA,SAASA,EAASC,GAA0B;AAC1C,QAAMC,IAAID,EAAS,YAAA;AACnB,SAAIC,MAAM,QAAc,kCACpBA,MAAM,aAAmB,kCACzBA,MAAM,UAAgB,gCACtBA,MAAM,UAAUA,MAAM,aAAmB,kCACzCA,MAAM,cAAoB,YACvB;AACT;AAMO,MAAMC,IAAgD,CAAC,EAAE,OAAAC,GAAO,WAAAC,QAAgB;AACrF,QAAMC,IAAOC,EAAQ,MAAMC,EAAmBJ,CAAK,GAAG,CAACA,CAAK,CAAC,GACvDK,IAAUH,EAAK,SAAS,IAAIA,EAAKA,EAAK,SAAS,CAAC,EAAG,QAAQ;AAEjE,MAAIA,EAAK,WAAW;AAClB,WACE,gBAAAI;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,aACE,gBAAAD,EAACE,EAAW,MAAX,EAAgB,MAAK,aAAY,UAAA,+BAAA,CAElC;AAAA,MAAA;AAAA,IAAA;AAMR,QAAMC,IAAQJ,IAAU,IAAIA,IAAU;AAEtC,2BACG,OAAA,EAAI,WAAWK,EAAWC,EAAO,QAAQV,CAAS,GACjD,UAAA;AAAA,IAAA,gBAAAK,EAAC,SAAI,WAAWK,EAAO,YACpB,UAAAT,EAAK,IAAI,CAACU,MAAQ;AACjB,YAAMC,IAAWD,EAAI,UAAUH,IAAS,KAClCK,IAAW,KAAK,IAAKF,EAAI,aAAaH,IAAS,KAAK,IAAI,GACxDM,IAAOH,EAAI,aAAaH,IAAQ;AACtC,aACE,gBAAAO,EAAC,OAAA,EAAwC,WAAWL,EAAO,WACzD,UAAA;AAAA,QAAA,gBAAAL,EAAC,OAAA,EAAI,WAAWK,EAAO,aAAa,OAAOC,EAAI,OAC5C,YAAI,MAAA,CACP;AAAA,0BACC,OAAA,EAAI,WAAWD,EAAO,aAAa,eAAW,IAC7C,UAAA,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWI,EAAWC,EAAO,WAAWI,KAAQJ,EAAO,aAAa;AAAA,YACpE,OAAO;AAAA,cACL,MAAM,GAAGE,CAAO;AAAA,cAChB,OAAOE,IAAO,SAAY,GAAGD,CAAQ;AAAA,cACrC,YAAYlB,EAASgB,EAAI,QAAQ;AAAA,YAAA;AAAA,UACnC;AAAA,QAAA,GAEJ;AAAA,QACA,gBAAAI,EAAC,OAAA,EAAI,WAAWL,EAAO,UAAW,UAAA;AAAA,UAAAC,EAAI;AAAA,UAAW;AAAA,QAAA,EAAA,CAAG;AAAA,MAAA,EAAA,GAd5C,GAAGA,EAAI,KAAK,IAAIA,EAAI,OAAO,EAerC;AAAA,IAEJ,CAAC,EAAA,CACH;AAAA,IACA,gBAAAI,EAAC,OAAA,EAAI,WAAWL,EAAO,YACrB,UAAA;AAAA,MAAA,gBAAAL,EAAC,QAAA,EAAK;AAAA,MACN,gBAAAU,EAACR,EAAW,MAAX,EAAgB,QAAM,IAAE,UAAA;AAAA,QAAAH;AAAA,QAAQ;AAAA,MAAA,EAAA,CAAG;AAAA,IAAA,EAAA,CACtC;AAAA,EAAA,GACF;AAEJ;"}
@@ -16,4 +16,8 @@ export declare const LazyLine: {
16
16
  (props: Record<string, unknown>): import("react").JSX.Element;
17
17
  displayName: string;
18
18
  };
19
+ export declare const LazyPie: {
20
+ (props: Record<string, unknown>): import("react").JSX.Element;
21
+ displayName: string;
22
+ };
19
23
  export {};
@@ -8,28 +8,29 @@ function z(t) {
8
8
  const r = t[0];
9
9
  return r == null || typeof r != "object" || m(r) ? !1 : "type" in r;
10
10
  }
11
- function l(t) {
11
+ function i(t) {
12
12
  const r = h(() => p(t));
13
- function s(i) {
14
- const e = typeof i.height == "number" ? i.height : 300, { containerStyle: o, marks: c, children: y, ...f } = i, u = {
13
+ function s(o) {
14
+ const e = typeof o.height == "number" ? o.height : 300, { containerStyle: a, marks: c, children: y, ...f } = o, u = {
15
15
  width: "100%",
16
16
  height: e,
17
- ...typeof o == "object" && o ? o : {}
18
- }, a = {
17
+ ...typeof a == "object" && a ? a : {}
18
+ }, l = {
19
19
  ...f,
20
20
  height: e,
21
21
  autoFit: !0,
22
22
  containerStyle: u
23
23
  };
24
- return c !== void 0 ? a.children = c : z(y) && (a.children = y), /* @__PURE__ */ n(L, { height: e, children: /* @__PURE__ */ n(d, { fallback: /* @__PURE__ */ n("div", { style: { height: e }, "aria-hidden": !0 }), children: /* @__PURE__ */ n(r, { ...a }) }) });
24
+ return c !== void 0 ? l.children = c : z(y) && (l.children = y), /* @__PURE__ */ n(L, { height: e, children: /* @__PURE__ */ n(d, { fallback: /* @__PURE__ */ n("div", { style: { height: e }, "aria-hidden": !0 }), children: /* @__PURE__ */ n(r, { ...l }) }) });
25
25
  }
26
26
  return s.displayName = `Lazy${String(t)}`, s;
27
27
  }
28
- const b = l("Bar"), j = l("Column"), k = l("Line");
28
+ i("Bar");
29
+ const b = i("Column"), j = i("Line"), k = i("Pie");
29
30
  export {
30
- b as LazyBar,
31
- j as LazyColumn,
32
- k as LazyLine,
33
- l as createLazyPlot
31
+ b as LazyColumn,
32
+ j as LazyLine,
33
+ k as LazyPie,
34
+ i as createLazyPlot
34
35
  };
35
36
  //# sourceMappingURL=createLazyPlot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createLazyPlot.js","sources":["../../../../src/components/Audit/Chart/createLazyPlot.tsx"],"sourcesContent":["import { lazy, Suspense, isValidElement, type ComponentType } from 'react';\nimport ChartLazyBoundary from './ChartLazyBoundary';\nimport { loadChartExport } from './loadChartExport';\n\ntype ChartsModule = typeof import('@ant-design/charts');\n\nfunction isPlotMarkList(value: unknown): value is Record<string, unknown>[] {\n if (!Array.isArray(value)) return false;\n if (value.length === 0) return true;\n const first = value[0];\n if (first == null || typeof first !== 'object' || isValidElement(first)) return false;\n return 'type' in first;\n}\n\n/** Audit 内懒加载图种;定高避免 height:inherit → 空白 */\nexport function createLazyPlot<K extends keyof ChartsModule>(exportName: K) {\n const Plot = lazy(() => loadChartExport(exportName)) as unknown as ComponentType<\n Record<string, unknown>\n >;\n\n function LazyPlot(props: Record<string, unknown>) {\n const height = typeof props.height === 'number' ? props.height : 300;\n const { containerStyle: userContainerStyle, marks, children, ...rest } = props;\n const containerStyle = {\n width: '100%',\n height,\n ...(typeof userContainerStyle === 'object' && userContainerStyle\n ? (userContainerStyle as Record<string, unknown>)\n : {}),\n };\n const plotProps: Record<string, unknown> = {\n ...rest,\n height,\n autoFit: true,\n containerStyle,\n };\n if (marks !== undefined) {\n plotProps.children = marks;\n } else if (isPlotMarkList(children)) {\n plotProps.children = children;\n }\n\n return (\n <ChartLazyBoundary height={height}>\n <Suspense fallback={<div style={{ height }} aria-hidden />}>\n <Plot {...plotProps} />\n </Suspense>\n </ChartLazyBoundary>\n );\n }\n\n LazyPlot.displayName = `Lazy${String(exportName)}`;\n return LazyPlot;\n}\n\nexport const LazyBar = createLazyPlot('Bar');\nexport const LazyColumn = createLazyPlot('Column');\nexport const LazyLine = createLazyPlot('Line');\n"],"names":["isPlotMarkList","value","first","isValidElement","createLazyPlot","exportName","Plot","lazy","loadChartExport","LazyPlot","props","height","userContainerStyle","marks","children","rest","containerStyle","plotProps","jsx","ChartLazyBoundary","Suspense","LazyBar","LazyColumn","LazyLine"],"mappings":";;;;AAMA,SAASA,EAAeC,GAAoD;AAC1E,MAAI,CAAC,MAAM,QAAQA,CAAK,EAAG,QAAO;AAClC,MAAIA,EAAM,WAAW,EAAG,QAAO;AAC/B,QAAMC,IAAQD,EAAM,CAAC;AACrB,SAAIC,KAAS,QAAQ,OAAOA,KAAU,YAAYC,EAAeD,CAAK,IAAU,KACzE,UAAUA;AACnB;AAGO,SAASE,EAA6CC,GAAe;AAC1E,QAAMC,IAAOC,EAAK,MAAMC,EAAgBH,CAAU,CAAC;AAInD,WAASI,EAASC,GAAgC;AAChD,UAAMC,IAAS,OAAOD,EAAM,UAAW,WAAWA,EAAM,SAAS,KAC3D,EAAE,gBAAgBE,GAAoB,OAAAC,GAAO,UAAAC,GAAU,GAAGC,MAASL,GACnEM,IAAiB;AAAA,MACrB,OAAO;AAAA,MACP,QAAAL;AAAA,MACA,GAAI,OAAOC,KAAuB,YAAYA,IACzCA,IACD,CAAA;AAAA,IAAC,GAEDK,IAAqC;AAAA,MACzC,GAAGF;AAAA,MACH,QAAAJ;AAAA,MACA,SAAS;AAAA,MACT,gBAAAK;AAAA,IAAA;AAEF,WAAIH,MAAU,SACZI,EAAU,WAAWJ,IACZb,EAAec,CAAQ,MAChCG,EAAU,WAAWH,IAIrB,gBAAAI,EAACC,KAAkB,QAAAR,GACjB,UAAA,gBAAAO,EAACE,KAAS,UAAU,gBAAAF,EAAC,SAAI,OAAO,EAAE,QAAAP,KAAU,eAAW,IAAC,GACtD,UAAA,gBAAAO,EAACZ,KAAM,GAAGW,GAAW,GACvB,EAAA,CACF;AAAA,EAEJ;AAEA,SAAAR,EAAS,cAAc,OAAO,OAAOJ,CAAU,CAAC,IACzCI;AACT;AAEO,MAAMY,IAAUjB,EAAe,KAAK,GAC9BkB,IAAalB,EAAe,QAAQ,GACpCmB,IAAWnB,EAAe,MAAM;"}
1
+ {"version":3,"file":"createLazyPlot.js","sources":["../../../../src/components/Audit/Chart/createLazyPlot.tsx"],"sourcesContent":["import { lazy, Suspense, isValidElement, type ComponentType } from 'react';\nimport ChartLazyBoundary from './ChartLazyBoundary';\nimport { loadChartExport } from './loadChartExport';\n\ntype ChartsModule = typeof import('@ant-design/charts');\n\nfunction isPlotMarkList(value: unknown): value is Record<string, unknown>[] {\n if (!Array.isArray(value)) return false;\n if (value.length === 0) return true;\n const first = value[0];\n if (first == null || typeof first !== 'object' || isValidElement(first)) return false;\n return 'type' in first;\n}\n\n/** Audit 内懒加载图种;定高避免 height:inherit → 空白 */\nexport function createLazyPlot<K extends keyof ChartsModule>(exportName: K) {\n const Plot = lazy(() => loadChartExport(exportName)) as unknown as ComponentType<\n Record<string, unknown>\n >;\n\n function LazyPlot(props: Record<string, unknown>) {\n const height = typeof props.height === 'number' ? props.height : 300;\n const { containerStyle: userContainerStyle, marks, children, ...rest } = props;\n const containerStyle = {\n width: '100%',\n height,\n ...(typeof userContainerStyle === 'object' && userContainerStyle\n ? (userContainerStyle as Record<string, unknown>)\n : {}),\n };\n const plotProps: Record<string, unknown> = {\n ...rest,\n height,\n autoFit: true,\n containerStyle,\n };\n if (marks !== undefined) {\n plotProps.children = marks;\n } else if (isPlotMarkList(children)) {\n plotProps.children = children;\n }\n\n return (\n <ChartLazyBoundary height={height}>\n <Suspense fallback={<div style={{ height }} aria-hidden />}>\n <Plot {...plotProps} />\n </Suspense>\n </ChartLazyBoundary>\n );\n }\n\n LazyPlot.displayName = `Lazy${String(exportName)}`;\n return LazyPlot;\n}\n\nexport const LazyBar = createLazyPlot('Bar');\nexport const LazyColumn = createLazyPlot('Column');\nexport const LazyLine = createLazyPlot('Line');\nexport const LazyPie = createLazyPlot('Pie');\n"],"names":["isPlotMarkList","value","first","isValidElement","createLazyPlot","exportName","Plot","lazy","loadChartExport","LazyPlot","props","height","userContainerStyle","marks","children","rest","containerStyle","plotProps","jsx","ChartLazyBoundary","Suspense","LazyColumn","LazyLine","LazyPie"],"mappings":";;;;AAMA,SAASA,EAAeC,GAAoD;AAC1E,MAAI,CAAC,MAAM,QAAQA,CAAK,EAAG,QAAO;AAClC,MAAIA,EAAM,WAAW,EAAG,QAAO;AAC/B,QAAMC,IAAQD,EAAM,CAAC;AACrB,SAAIC,KAAS,QAAQ,OAAOA,KAAU,YAAYC,EAAeD,CAAK,IAAU,KACzE,UAAUA;AACnB;AAGO,SAASE,EAA6CC,GAAe;AAC1E,QAAMC,IAAOC,EAAK,MAAMC,EAAgBH,CAAU,CAAC;AAInD,WAASI,EAASC,GAAgC;AAChD,UAAMC,IAAS,OAAOD,EAAM,UAAW,WAAWA,EAAM,SAAS,KAC3D,EAAE,gBAAgBE,GAAoB,OAAAC,GAAO,UAAAC,GAAU,GAAGC,MAASL,GACnEM,IAAiB;AAAA,MACrB,OAAO;AAAA,MACP,QAAAL;AAAA,MACA,GAAI,OAAOC,KAAuB,YAAYA,IACzCA,IACD,CAAA;AAAA,IAAC,GAEDK,IAAqC;AAAA,MACzC,GAAGF;AAAA,MACH,QAAAJ;AAAA,MACA,SAAS;AAAA,MACT,gBAAAK;AAAA,IAAA;AAEF,WAAIH,MAAU,SACZI,EAAU,WAAWJ,IACZb,EAAec,CAAQ,MAChCG,EAAU,WAAWH,IAIrB,gBAAAI,EAACC,KAAkB,QAAAR,GACjB,UAAA,gBAAAO,EAACE,KAAS,UAAU,gBAAAF,EAAC,SAAI,OAAO,EAAE,QAAAP,KAAU,eAAW,IAAC,GACtD,UAAA,gBAAAO,EAACZ,KAAM,GAAGW,GAAW,GACvB,EAAA,CACF;AAAA,EAEJ;AAEA,SAAAR,EAAS,cAAc,OAAO,OAAOJ,CAAU,CAAC,IACzCI;AACT;AAEuBL,EAAe,KAAK;AACpC,MAAMiB,IAAajB,EAAe,QAAQ,GACpCkB,IAAWlB,EAAe,MAAM,GAChCmB,IAAUnB,EAAe,KAAK;"}
@@ -11,8 +11,13 @@ export type AuditDetailKpi = {
11
11
  };
12
12
  export declare function computeDetailKpi(detail: AuditEventDetail | null | undefined): AuditDetailKpi;
13
13
  export declare function isErrorStep(s: AuditStep): boolean;
14
- /** 瀑布图数据:仅 title + durationMs,不含 SQL 原文 */
15
- export declare function waterfallChartData(steps: AuditStep[]): Array<{
14
+ /** 区间甘特条:按 seq 累加起点(采集仅 durationMs,非墙钟并行) */
15
+ export type WaterfallChartBar = {
16
16
  title: string;
17
+ startMs: number;
18
+ endMs: number;
17
19
  durationMs: number;
18
- }>;
20
+ stepType: string;
21
+ };
22
+ /** 瀑布/甘特图数据:title + [startMs,endMs],不含 SQL 原文 */
23
+ export declare function waterfallChartData(steps: AuditStep[]): WaterfallChartBar[];
@@ -1,28 +1,36 @@
1
- function o(t) {
2
- const e = (t == null ? void 0 : t.steps) || [];
3
- let n = 0, s = null, u = !1;
4
- for (const r of e)
5
- r.stepType === "SQL" && (n += 1), typeof r.durationMs == "number" && Number.isFinite(r.durationMs) && (u = !0, (!s || r.durationMs > s.durationMs) && (s = { title: r.title || r.stepType, durationMs: r.durationMs }));
1
+ function a(s) {
2
+ const o = (s == null ? void 0 : s.steps) || [];
3
+ let r = 0, t = null, n = !1;
4
+ for (const e of o)
5
+ e.stepType === "SQL" && (r += 1), typeof e.durationMs == "number" && Number.isFinite(e.durationMs) && (n = !0, (!t || e.durationMs > t.durationMs) && (t = { title: e.title || e.stepType, durationMs: e.durationMs }));
6
6
  return {
7
- durationMs: typeof (t == null ? void 0 : t.durationMs) == "number" ? t.durationMs : null,
8
- stepCount: e.length,
9
- sqlCount: n,
10
- slowestStep: s,
11
- hasAnyStepMs: u
7
+ durationMs: typeof (s == null ? void 0 : s.durationMs) == "number" ? s.durationMs : null,
8
+ stepCount: o.length,
9
+ sqlCount: r,
10
+ slowestStep: t,
11
+ hasAnyStepMs: n
12
12
  };
13
13
  }
14
- function i(t) {
15
- return t.stepType === "ERROR" || t.status === "error" || t.status === "fail";
14
+ function M(s) {
15
+ return s.stepType === "ERROR" || s.status === "error" || s.status === "fail";
16
16
  }
17
- function p(t) {
18
- return t.filter((e) => typeof e.durationMs == "number" && Number.isFinite(e.durationMs)).map((e) => ({
19
- title: e.title || e.stepType || "step",
20
- durationMs: e.durationMs
21
- }));
17
+ function f(s) {
18
+ const o = s.filter((t) => typeof t.durationMs == "number" && Number.isFinite(t.durationMs)).slice().sort((t, n) => t.seq - n.seq);
19
+ let r = 0;
20
+ return o.map((t) => {
21
+ const n = t.durationMs, e = t.title || t.stepType || "step", i = `${t.seq}. ${e}`, p = r, u = r + n;
22
+ return r = u, {
23
+ title: i,
24
+ startMs: p,
25
+ endMs: u,
26
+ durationMs: n,
27
+ stepType: String(t.stepType || "")
28
+ };
29
+ });
22
30
  }
23
31
  export {
24
- o as computeDetailKpi,
25
- i as isErrorStep,
26
- p as waterfallChartData
32
+ a as computeDetailKpi,
33
+ M as isErrorStep,
34
+ f as waterfallChartData
27
35
  };
28
36
  //# sourceMappingURL=detailKpi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"detailKpi.js","sources":["../../../src/components/Audit/detailKpi.ts"],"sourcesContent":["import type { AuditEventDetail, AuditStep } from './types';\n\nexport type AuditDetailKpi = {\n durationMs: number | null;\n stepCount: number;\n sqlCount: number;\n slowestStep: { title: string; durationMs: number } | null;\n hasAnyStepMs: boolean;\n};\n\nexport function computeDetailKpi(detail: AuditEventDetail | null | undefined): AuditDetailKpi {\n const steps = detail?.steps || [];\n let sqlCount = 0;\n let slowest: { title: string; durationMs: number } | null = null;\n let hasAnyStepMs = false;\n for (const s of steps) {\n if (s.stepType === 'SQL') sqlCount += 1;\n if (typeof s.durationMs === 'number' && Number.isFinite(s.durationMs)) {\n hasAnyStepMs = true;\n if (!slowest || s.durationMs > slowest.durationMs) {\n slowest = { title: s.title || s.stepType, durationMs: s.durationMs };\n }\n }\n }\n return {\n durationMs: typeof detail?.durationMs === 'number' ? detail.durationMs : null,\n stepCount: steps.length,\n sqlCount,\n slowestStep: slowest,\n hasAnyStepMs,\n };\n}\n\nexport function isErrorStep(s: AuditStep): boolean {\n return s.stepType === 'ERROR' || s.status === 'error' || s.status === 'fail';\n}\n\n/** 瀑布图数据:仅 title + durationMs,不含 SQL 原文 */\nexport function waterfallChartData(\n steps: AuditStep[],\n): Array<{ title: string; durationMs: number }> {\n return steps\n .filter((s) => typeof s.durationMs === 'number' && Number.isFinite(s.durationMs))\n .map((s) => ({\n title: s.title || s.stepType || 'step',\n durationMs: s.durationMs as number,\n }));\n}\n"],"names":["computeDetailKpi","detail","steps","sqlCount","slowest","hasAnyStepMs","s","isErrorStep","waterfallChartData"],"mappings":"AAUO,SAASA,EAAiBC,GAA6D;AAC5F,QAAMC,KAAQD,KAAA,gBAAAA,EAAQ,UAAS,CAAA;AAC/B,MAAIE,IAAW,GACXC,IAAwD,MACxDC,IAAe;AACnB,aAAWC,KAAKJ;AACd,IAAII,EAAE,aAAa,UAAOH,KAAY,IAClC,OAAOG,EAAE,cAAe,YAAY,OAAO,SAASA,EAAE,UAAU,MAClED,IAAe,KACX,CAACD,KAAWE,EAAE,aAAaF,EAAQ,gBACrCA,IAAU,EAAE,OAAOE,EAAE,SAASA,EAAE,UAAU,YAAYA,EAAE,WAAA;AAI9D,SAAO;AAAA,IACL,YAAY,QAAOL,KAAA,gBAAAA,EAAQ,eAAe,WAAWA,EAAO,aAAa;AAAA,IACzE,WAAWC,EAAM;AAAA,IACjB,UAAAC;AAAA,IACA,aAAaC;AAAA,IACb,cAAAC;AAAA,EAAA;AAEJ;AAEO,SAASE,EAAYD,GAAuB;AACjD,SAAOA,EAAE,aAAa,WAAWA,EAAE,WAAW,WAAWA,EAAE,WAAW;AACxE;AAGO,SAASE,EACdN,GAC8C;AAC9C,SAAOA,EACJ,OAAO,CAACI,MAAM,OAAOA,EAAE,cAAe,YAAY,OAAO,SAASA,EAAE,UAAU,CAAC,EAC/E,IAAI,CAACA,OAAO;AAAA,IACX,OAAOA,EAAE,SAASA,EAAE,YAAY;AAAA,IAChC,YAAYA,EAAE;AAAA,EAAA,EACd;AACN;"}
1
+ {"version":3,"file":"detailKpi.js","sources":["../../../src/components/Audit/detailKpi.ts"],"sourcesContent":["import type { AuditEventDetail, AuditStep } from './types';\n\nexport type AuditDetailKpi = {\n durationMs: number | null;\n stepCount: number;\n sqlCount: number;\n slowestStep: { title: string; durationMs: number } | null;\n hasAnyStepMs: boolean;\n};\n\nexport function computeDetailKpi(detail: AuditEventDetail | null | undefined): AuditDetailKpi {\n const steps = detail?.steps || [];\n let sqlCount = 0;\n let slowest: { title: string; durationMs: number } | null = null;\n let hasAnyStepMs = false;\n for (const s of steps) {\n if (s.stepType === 'SQL') sqlCount += 1;\n if (typeof s.durationMs === 'number' && Number.isFinite(s.durationMs)) {\n hasAnyStepMs = true;\n if (!slowest || s.durationMs > slowest.durationMs) {\n slowest = { title: s.title || s.stepType, durationMs: s.durationMs };\n }\n }\n }\n return {\n durationMs: typeof detail?.durationMs === 'number' ? detail.durationMs : null,\n stepCount: steps.length,\n sqlCount,\n slowestStep: slowest,\n hasAnyStepMs,\n };\n}\n\nexport function isErrorStep(s: AuditStep): boolean {\n return s.stepType === 'ERROR' || s.status === 'error' || s.status === 'fail';\n}\n\n/** 区间甘特条:按 seq 累加起点(采集仅 durationMs,非墙钟并行) */\nexport type WaterfallChartBar = {\n title: string;\n startMs: number;\n endMs: number;\n durationMs: number;\n stepType: string;\n};\n\n/** 瀑布/甘特图数据:title + [startMs,endMs],不含 SQL 原文 */\nexport function waterfallChartData(steps: AuditStep[]): WaterfallChartBar[] {\n const timed = steps\n .filter((s) => typeof s.durationMs === 'number' && Number.isFinite(s.durationMs))\n .slice()\n .sort((a, b) => a.seq - b.seq);\n\n let cursor = 0;\n return timed.map((s) => {\n const durationMs = s.durationMs as number;\n const raw = s.title || s.stepType || 'step';\n // 一律带 seq,避免同名只给部分加前缀造成「有的有序号、有的没有」\n const title = `${s.seq}. ${raw}`;\n const startMs = cursor;\n const endMs = cursor + durationMs;\n cursor = endMs;\n return {\n title,\n startMs,\n endMs,\n durationMs,\n stepType: String(s.stepType || ''),\n };\n });\n}\n"],"names":["computeDetailKpi","detail","steps","sqlCount","slowest","hasAnyStepMs","s","isErrorStep","waterfallChartData","timed","a","b","cursor","durationMs","raw","title","startMs","endMs"],"mappings":"AAUO,SAASA,EAAiBC,GAA6D;AAC5F,QAAMC,KAAQD,KAAA,gBAAAA,EAAQ,UAAS,CAAA;AAC/B,MAAIE,IAAW,GACXC,IAAwD,MACxDC,IAAe;AACnB,aAAWC,KAAKJ;AACd,IAAII,EAAE,aAAa,UAAOH,KAAY,IAClC,OAAOG,EAAE,cAAe,YAAY,OAAO,SAASA,EAAE,UAAU,MAClED,IAAe,KACX,CAACD,KAAWE,EAAE,aAAaF,EAAQ,gBACrCA,IAAU,EAAE,OAAOE,EAAE,SAASA,EAAE,UAAU,YAAYA,EAAE,WAAA;AAI9D,SAAO;AAAA,IACL,YAAY,QAAOL,KAAA,gBAAAA,EAAQ,eAAe,WAAWA,EAAO,aAAa;AAAA,IACzE,WAAWC,EAAM;AAAA,IACjB,UAAAC;AAAA,IACA,aAAaC;AAAA,IACb,cAAAC;AAAA,EAAA;AAEJ;AAEO,SAASE,EAAY,GAAuB;AACjD,SAAO,EAAE,aAAa,WAAW,EAAE,WAAW,WAAW,EAAE,WAAW;AACxE;AAYO,SAASC,EAAmBN,GAAyC;AAC1E,QAAMO,IAAQP,EACX,OAAO,CAACI,MAAM,OAAOA,EAAE,cAAe,YAAY,OAAO,SAASA,EAAE,UAAU,CAAC,EAC/E,QACA,KAAK,CAACI,GAAGC,MAAMD,EAAE,MAAMC,EAAE,GAAG;AAE/B,MAAIC,IAAS;AACb,SAAOH,EAAM,IAAI,CAACH,MAAM;AACtB,UAAMO,IAAaP,EAAE,YACfQ,IAAMR,EAAE,SAASA,EAAE,YAAY,QAE/BS,IAAQ,GAAGT,EAAE,GAAG,KAAKQ,CAAG,IACxBE,IAAUJ,GACVK,IAAQL,IAASC;AACvB,WAAAD,IAASK,GACF;AAAA,MACL,OAAAF;AAAA,MACA,SAAAC;AAAA,MACA,OAAAC;AAAA,MACA,YAAAJ;AAAA,MACA,UAAU,OAAOP,EAAE,YAAY,EAAE;AAAA,IAAA;AAAA,EAErC,CAAC;AACH;"}
@@ -1,12 +1,14 @@
1
- export { AuditLogList, AuditEventDetailView, AuditStepContent, default } from './AuditLogList';
1
+ export { AuditLogList, AuditEventDetailView, AuditStepContent, AuditStepHeader, default, } from './AuditLogList';
2
2
  export type { AuditLogListProps, AuditLogListMode } from './AuditLogList';
3
3
  export { AuditDayStatsBar } from './AuditDayStatsBar';
4
4
  export type { AuditDayStatsBarProps } from './AuditDayStatsBar';
5
5
  export { AuditWaterfall } from './AuditWaterfall';
6
6
  export type { AuditWaterfallProps } from './AuditWaterfall';
7
+ export { AuditStepPerfChart } from './AuditStepPerfChart';
8
+ export type { AuditStepPerfChartProps } from './AuditStepPerfChart';
7
9
  export { AuditPerfDashboard } from './AuditPerfDashboard';
8
10
  export type { AuditPerfDashboardProps } from './AuditPerfDashboard';
9
11
  export { displayActionLabel, displaySummary, labelOfAction, allActionLabels } from './labels';
10
12
  export { computeDetailKpi, waterfallChartData, isErrorStep } from './detailKpi';
11
- export type { AuditDetailKpi } from './detailKpi';
13
+ export type { AuditDetailKpi, WaterfallChartBar } from './detailKpi';
12
14
  export type { AuditEventDetail, AuditEventListItem, AuditStep, AuditStepType, AuditDayStats, AuditDashboardData, AuditDashboardDaily, AuditDashboardTopAction, } from './types';