Files
gongxue-base/apps/admin/src/components/AiChat/reviewSection.ts

116 lines
3.4 KiB
TypeScript

import type { AiReviewSection, AiReviewSectionStatus, AiReviewSectionType } from './types';
export const SECTION_TYPE_LABELS: Record<AiReviewSectionType, string> = {
students: '学生',
rooms: '宿舍',
transfers: '换宿',
checkins: '入住记录',
};
export const SECTION_ORDER: AiReviewSectionType[] = ['students', 'rooms', 'transfers', 'checkins'];
const SECTION_DEPENDENCIES: Record<AiReviewSectionType, AiReviewSectionType[]> = {
students: [],
rooms: [],
transfers: ['students', 'rooms'],
checkins: [],
};
export function sectionType(section: Pick<AiReviewSection, 'key' | 'type'>): AiReviewSectionType {
if (
section.type === 'students' ||
section.type === 'rooms' ||
section.type === 'transfers' ||
section.type === 'checkins'
) {
return section.type;
}
const key = section.key as AiReviewSectionType;
if (key === 'students' || key === 'rooms' || key === 'transfers' || key === 'checkins') {
return key;
}
const prefix = SECTION_ORDER.find((type) => section.key.startsWith(`${type}_`));
return prefix ?? 'students';
}
export function sectionCount(section: AiReviewSection): number {
return section.rows.length;
}
export function sectionStatus(section: AiReviewSection): AiReviewSectionStatus {
return section.status ?? 'pending';
}
export function sectionResultText(section: AiReviewSection): string {
if (!section.resultSummary) return '';
try {
const parsed = JSON.parse(section.resultSummary) as { message?: unknown };
if (typeof parsed.message === 'string') return parsed.message;
} catch {
// Older data may store a plain text summary.
}
return section.resultSummary;
}
export const SECTION_STATUS_LABELS: Record<AiReviewSectionStatus, string> = {
pending: '待确认',
submitted: '已导入',
failed: '失败',
skipped: '已跳过',
};
export type GroupStatus = 'pending' | 'partial' | 'submitted' | 'failed' | 'importing';
export const GROUP_STATUS_LABELS: Record<GroupStatus, string> = {
pending: '待确认',
partial: '部分完成',
submitted: '已导入',
failed: '失败',
importing: '导入中',
};
export function groupSections(
sections: AiReviewSection[],
type: AiReviewSectionType,
): AiReviewSection[] {
return sections.filter((section) => sectionType(section) === type);
}
export function groupStatus(
sections: AiReviewSection[],
type: AiReviewSectionType,
submittingKey: string | null,
submittingGroup: boolean,
activeType?: AiReviewSectionType,
): GroupStatus {
const items = groupSections(sections, type);
if (items.length === 0) return 'pending';
if (
(submittingGroup && type === activeType) ||
items.some((item) => submittingKey === item.key)
) {
return 'importing';
}
if (items.some((item) => sectionStatus(item) === 'failed')) return 'failed';
if (items.every((item) => sectionStatus(item) === 'submitted')) return 'submitted';
return 'partial';
}
export function dependencyHint(
sections: AiReviewSection[],
type: AiReviewSectionType,
): { step: number; title: string } | null {
for (const dependencyType of SECTION_DEPENDENCIES[type] ?? []) {
const matches = groupSections(sections, dependencyType);
if (matches.length === 0) {
return { step: -1, title: SECTION_TYPE_LABELS[dependencyType] };
}
for (const section of matches) {
if (sectionStatus(section) !== 'submitted') {
return { step: sections.indexOf(section), title: section.title };
}
}
}
return null;
}