Files
gongxue-base/apps/admin/src/components/AiChat/uiArtifacts.ts
wangziqi 4b60e0c018 fix: code-review 审查问题修复 + A2UI 测试补齐
Standards 轴:
- 移除 uiArtifacts.ts 的 payloadOf 死代码残留
- AttendanceDevices 残留 any 类型化(补 ClassroomOption.status 字段)
- 批量考勤纠错区分业务失败(已结算/无权限)与系统错误,
  前端提示精确到两类数量
- Dashboard queryFn 六段重复校验块收敛为 safeValidate 助手

Spec 轴:
- 补齐阶段 3.4 A2UI 测试:图表空数据占位、ArtifactErrorBoundary
  降级隔离、useSubmissionState/useXCardSurface 单测(7 用例)
- 阶段 2.2 补两处引导:教师工作台区分「今日无课」与「未分配班级」、
  班级花名册空态带「添加学员」动作
- 契约文档修正 DynamicReview 状态管理描述(多提交点如实说明)

aislop 剩余 16 警告均为必要豁免(类型边界/声明式 SQL 配置/既有文件规模)
2026-08-08 09:43:48 +08:00

69 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type {
AiArtifactSchema,
AiChartSchema,
AiChatMessage,
AiFormSchema,
AiReviewSchema,
} from './types';
export function mergeById<T extends { id: string }>(
current: T[] | undefined,
incoming: T | T[] | undefined,
): T[] {
const items = Array.isArray(incoming) ? incoming : incoming ? [incoming] : [];
if (!items.length) return current ?? [];
const next = [...(current ?? [])];
for (const item of items) {
if (!item || typeof item !== 'object') continue;
const index = next.findIndex((existing) => existing.id === item.id);
if (index === -1) {
next.push(item);
} else {
next[index] = item;
}
}
return next;
}
/**
* 将统一 artifact 归入 uiArtifacts。
*
* 注意:不再派发到 legacy 列表forms/reviews/charts——渲染层从
* uiArtifacts 派生legacy 字段仅保留给历史消息metadata 中只有
* a2uiForm/a2uiReview/a2uiChart 的老数据)作兼容读取。
*/
export function mergeArtifactIntoMessage(
message: AiChatMessage,
artifact: AiArtifactSchema,
): AiChatMessage {
message.uiArtifacts = mergeById<AiArtifactSchema>(message.uiArtifacts, artifact);
return message;
}
/**
* 从 uiArtifacts 派生 legacy 列表(渲染用)。
* 仅当 message 上没有显式 legacy 数据(历史消息)时,渲染层回退到 message.forms 等。
*/
export function deriveForms(message: AiChatMessage): AiFormSchema[] {
return (message.uiArtifacts ?? [])
.filter((artifact) => artifact.type === 'form')
.map((artifact) => artifact.payload)
.filter((payload): payload is AiFormSchema => Boolean(payload) && typeof payload === 'object');
}
export function deriveReviews(message: AiChatMessage): AiReviewSchema[] {
return (message.uiArtifacts ?? [])
.filter((artifact) => artifact.type === 'review')
.map((artifact) => artifact.payload)
.filter(
(payload): payload is AiReviewSchema => Boolean(payload) && typeof payload === 'object',
);
}
export function deriveCharts(message: AiChatMessage): AiChartSchema[] {
return (message.uiArtifacts ?? [])
.filter((artifact) => artifact.type === 'chart')
.map((artifact) => artifact.payload)
.filter((payload): payload is AiChartSchema => Boolean(payload) && typeof payload === 'object');
}