fix(ai): 清理 aislop 扫描告警
- 拆分 SSE reducer 到 sseReducer.ts,provider.ts 降至 220 行 - artifact 合并工具抽到 uiArtifacts.ts,去除双重类型断言 - 业务上下文注册表改用 field/relation/entity 构建器收敛重复 - aislop 分数 71 → 81(Healthy),AI Slop 0 告警
This commit is contained in:
@@ -1,8 +1,49 @@
|
||||
import type {
|
||||
BusinessEntity,
|
||||
BusinessEntityField,
|
||||
BusinessEntityRelation,
|
||||
BusinessWorkflow,
|
||||
} from './business-context.types';
|
||||
|
||||
function field(
|
||||
key: string,
|
||||
label: string,
|
||||
type: BusinessEntityField['type'],
|
||||
extra: Partial<Omit<BusinessEntityField, 'key' | 'label' | 'type'>> = {},
|
||||
): BusinessEntityField {
|
||||
return { key, label, type, ...extra };
|
||||
}
|
||||
|
||||
function relation(
|
||||
entityKey: string,
|
||||
via: string,
|
||||
requiredFor: readonly string[],
|
||||
): BusinessEntityRelation {
|
||||
return { entityKey, via, requiredFor };
|
||||
}
|
||||
|
||||
function entity(
|
||||
key: string,
|
||||
name: string,
|
||||
description: string,
|
||||
options: {
|
||||
searchTool?: string;
|
||||
requiredPermissions: readonly string[];
|
||||
fields: readonly BusinessEntityField[];
|
||||
relations?: readonly BusinessEntityRelation[];
|
||||
},
|
||||
): BusinessEntity {
|
||||
return {
|
||||
key,
|
||||
name,
|
||||
description,
|
||||
...(options.searchTool ? { searchTool: options.searchTool } : {}),
|
||||
requiredPermissions: options.requiredPermissions,
|
||||
fields: options.fields,
|
||||
relations: options.relations ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 恭学系统业务上下文(代码内维护)。
|
||||
*
|
||||
@@ -11,232 +52,191 @@ import type {
|
||||
* Agent 感知业务流程。
|
||||
*/
|
||||
export const BUSINESS_ENTITIES: readonly BusinessEntity[] = [
|
||||
{
|
||||
key: 'student',
|
||||
name: '学生档案',
|
||||
description: '学生基础档案(姓名、学号、手机号、性别等),是分班、入住、账单的前置数据。',
|
||||
entity('student', '学生档案', '学生基础档案(姓名、学号、手机号、性别等),是分班、入住、账单的前置数据。', {
|
||||
searchTool: 'search_students',
|
||||
requiredPermissions: ['student:view'],
|
||||
fields: [
|
||||
{ key: 'name', label: '姓名', type: 'string', required: true },
|
||||
{ key: 'studentNo', label: '学号', type: 'string' },
|
||||
{ key: 'phone', label: '手机号', type: 'string' },
|
||||
{ key: 'gender', label: '性别', type: 'enum', enumFrom: 'student.gender' },
|
||||
{ key: 'idNumber', label: '身份证号', type: 'string' },
|
||||
field('name', '姓名', 'string', { required: true }),
|
||||
field('studentNo', '学号', 'string'),
|
||||
field('phone', '手机号', 'string'),
|
||||
field('gender', '性别', 'enum', { enumFrom: 'student.gender' }),
|
||||
field('idNumber', '身份证号', 'string'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'class', via: 'class_student', requiredFor: ['class'] },
|
||||
{ entityKey: 'occupancy', via: 'occupancy', requiredFor: ['checkin'] },
|
||||
{ entityKey: 'bill', via: 'bill', requiredFor: ['bill'] },
|
||||
{ entityKey: 'exam', via: 'exam_score', requiredFor: ['exam'] },
|
||||
relation('class', 'class_student', ['class']),
|
||||
relation('occupancy', 'occupancy', ['checkin']),
|
||||
relation('bill', 'bill', ['bill']),
|
||||
relation('exam', 'exam_score', ['exam']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'class',
|
||||
name: '班级',
|
||||
description: '班级档案与在读分班关系,排课、考勤、考试依赖班级。',
|
||||
}),
|
||||
entity('class', '班级', '班级档案与在读分班关系,排课、考勤、考试依赖班级。', {
|
||||
searchTool: 'search_classes',
|
||||
requiredPermissions: ['class:view'],
|
||||
fields: [
|
||||
{ key: 'name', label: '班级名称', type: 'string', required: true },
|
||||
{ key: 'grade', label: '年级', type: 'string' },
|
||||
{ key: 'headTeacher', label: '班主任', type: 'string' },
|
||||
field('name', '班级名称', 'string', { required: true }),
|
||||
field('grade', '年级', 'string'),
|
||||
field('headTeacher', '班主任', 'string'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'student', via: 'class_student', requiredFor: ['class'] },
|
||||
{ entityKey: 'schedule', via: 'class_schedule', requiredFor: ['schedule'] },
|
||||
relation('student', 'class_student', ['class']),
|
||||
relation('schedule', 'class_schedule', ['schedule']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'schedule',
|
||||
name: '排课/日程',
|
||||
description: '班级与教室的课程安排,考勤和教室日程依赖排课。',
|
||||
}),
|
||||
entity('schedule', '排课/日程', '班级与教室的课程安排,考勤和教室日程依赖排课。', {
|
||||
searchTool: 'search_schedules',
|
||||
requiredPermissions: ['schedule:view'],
|
||||
fields: [
|
||||
{ key: 'classId', label: '班级', type: 'number' },
|
||||
{ key: 'classroomId', label: '教室', type: 'number' },
|
||||
{ key: 'weekDay', label: '星期', type: 'number' },
|
||||
{ key: 'startTime', label: '开始时间', type: 'string' },
|
||||
{ key: 'endTime', label: '结束时间', type: 'string' },
|
||||
field('classId', '班级', 'number'),
|
||||
field('classroomId', '教室', 'number'),
|
||||
field('weekDay', '星期', 'number'),
|
||||
field('startTime', '开始时间', 'string'),
|
||||
field('endTime', '结束时间', 'string'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'class', via: 'class_schedule', requiredFor: ['schedule'] },
|
||||
{ entityKey: 'classroom', via: 'class_schedule', requiredFor: ['schedule'] },
|
||||
relation('class', 'class_schedule', ['schedule']),
|
||||
relation('classroom', 'class_schedule', ['schedule']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'attendance',
|
||||
name: '考勤',
|
||||
description: '按班级与日期的考勤记录(出勤/迟到/缺勤/请假)。',
|
||||
}),
|
||||
entity('attendance', '考勤', '按班级与日期的考勤记录(出勤/迟到/缺勤/请假)。', {
|
||||
searchTool: 'get_attendance_summary',
|
||||
requiredPermissions: ['attendance:view'],
|
||||
fields: [
|
||||
{ key: 'studentId', label: '学生', type: 'number', required: true },
|
||||
{ key: 'date', label: '日期', type: 'date', required: true },
|
||||
{ key: 'status', label: '状态', type: 'enum', enumFrom: 'attendance.status' },
|
||||
field('studentId', '学生', 'number', { required: true }),
|
||||
field('date', '日期', 'date', { required: true }),
|
||||
field('status', '状态', 'enum', { enumFrom: 'attendance.status' }),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'class', via: 'class_schedule', requiredFor: ['attendance'] },
|
||||
{ entityKey: 'schedule', via: 'class_schedule', requiredFor: ['attendance'] },
|
||||
relation('class', 'class_schedule', ['attendance']),
|
||||
relation('schedule', 'class_schedule', ['attendance']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'exam',
|
||||
name: '考试/成绩',
|
||||
description: '考试安排与成绩记录,依赖班级与学生档案。',
|
||||
}),
|
||||
entity('exam', '考试/成绩', '考试安排与成绩记录,依赖班级与学生档案。', {
|
||||
searchTool: 'search_exams',
|
||||
requiredPermissions: ['exam:view'],
|
||||
fields: [
|
||||
{ key: 'name', label: '考试名称', type: 'string', required: true },
|
||||
{ key: 'date', label: '考试日期', type: 'date' },
|
||||
{ key: 'subject', label: '科目', type: 'string' },
|
||||
field('name', '考试名称', 'string', { required: true }),
|
||||
field('date', '考试日期', 'date'),
|
||||
field('subject', '科目', 'string'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'class', via: 'exam_score', requiredFor: ['exam'] },
|
||||
{ entityKey: 'student', via: 'exam_score', requiredFor: ['exam'] },
|
||||
relation('class', 'exam_score', ['exam']),
|
||||
relation('student', 'exam_score', ['exam']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'room',
|
||||
name: '宿舍档案',
|
||||
description: '宿舍/床位基础档案,入住登记的前置数据。',
|
||||
}),
|
||||
entity('room', '宿舍档案', '宿舍/床位基础档案,入住登记的前置数据。', {
|
||||
searchTool: 'search_rooms',
|
||||
requiredPermissions: ['room:view'],
|
||||
fields: [
|
||||
{ key: 'roomNumber', label: '宿舍号', type: 'string', required: true },
|
||||
{ key: 'building', label: '楼栋', type: 'string' },
|
||||
{ key: 'floor', label: '楼层', type: 'number' },
|
||||
{ key: 'capacity', label: '容量', type: 'number', required: true },
|
||||
{ key: 'roomType', label: '房型', type: 'string' },
|
||||
{ key: 'monthlyRate', label: '月租金', type: 'number' },
|
||||
field('roomNumber', '宿舍号', 'string', { required: true }),
|
||||
field('building', '楼栋', 'string'),
|
||||
field('floor', '楼层', 'number'),
|
||||
field('capacity', '容量', 'number', { required: true }),
|
||||
field('roomType', '房型', 'string'),
|
||||
field('monthlyRate', '月租金', 'number'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'occupancy', via: 'occupancy', requiredFor: ['checkin'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'occupancy',
|
||||
name: '入住记录',
|
||||
description: '学生入住/换宿/退宿记录,费用与账单依赖入住状态。',
|
||||
relations: [relation('occupancy', 'occupancy', ['checkin'])],
|
||||
}),
|
||||
entity('occupancy', '入住记录', '学生入住/换宿/退宿记录,费用与账单依赖入住状态。', {
|
||||
searchTool: 'get_room_occupancy_summary',
|
||||
requiredPermissions: ['occupancy:view'],
|
||||
fields: [
|
||||
{ key: 'studentId', label: '学生', type: 'number', required: true },
|
||||
{ key: 'roomId', label: '宿舍', type: 'number', required: true },
|
||||
{ key: 'checkInDate', label: '入住日期', type: 'date', required: true },
|
||||
{ key: 'billingStartDate', label: '计费开始日期', type: 'date', required: true },
|
||||
{ key: 'stayType', label: '住宿类型', type: 'enum', enumFrom: 'occupancy.stayType' },
|
||||
field('studentId', '学生', 'number', { required: true }),
|
||||
field('roomId', '宿舍', 'number', { required: true }),
|
||||
field('checkInDate', '入住日期', 'date', { required: true }),
|
||||
field('billingStartDate', '计费开始日期', 'date', { required: true }),
|
||||
field('stayType', '住宿类型', 'enum', { enumFrom: 'occupancy.stayType' }),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'student', via: 'occupancy', requiredFor: ['checkin'] },
|
||||
{ entityKey: 'room', via: 'occupancy', requiredFor: ['checkin'] },
|
||||
{ entityKey: 'bill', via: 'bill', requiredFor: ['bill'] },
|
||||
relation('student', 'occupancy', ['checkin']),
|
||||
relation('room', 'occupancy', ['checkin']),
|
||||
relation('bill', 'bill', ['bill']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'expense',
|
||||
name: '费用',
|
||||
description: '公共费用与个人费用,是生成账单的基础。',
|
||||
}),
|
||||
entity('expense', '费用', '公共费用与个人费用,是生成账单的基础。', {
|
||||
searchTool: 'search_expenses',
|
||||
requiredPermissions: ['expense:view'],
|
||||
fields: [
|
||||
{ key: 'type', label: '费用类型', type: 'string', required: true },
|
||||
{ key: 'amount', label: '金额', type: 'number', required: true },
|
||||
{ key: 'periodStart', label: '费用开始日期', type: 'date' },
|
||||
{ key: 'periodEnd', label: '费用结束日期', type: 'date' },
|
||||
field('type', '费用类型', 'string', { required: true }),
|
||||
field('amount', '金额', 'number', { required: true }),
|
||||
field('periodStart', '费用开始日期', 'date'),
|
||||
field('periodEnd', '费用结束日期', 'date'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'occupancy', via: 'expense', requiredFor: ['expense'] },
|
||||
{ entityKey: 'bill', via: 'bill_item', requiredFor: ['bill'] },
|
||||
relation('occupancy', 'expense', ['expense']),
|
||||
relation('bill', 'bill_item', ['bill']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'bill',
|
||||
name: '账单',
|
||||
description: '按学生与账期生成的账单(公共+个人费用分摊),支持确认与付款。',
|
||||
}),
|
||||
entity('bill', '账单', '按学生与账期生成的账单(公共+个人费用分摊),支持确认与付款。', {
|
||||
searchTool: 'search_bills',
|
||||
requiredPermissions: ['bill:view'],
|
||||
fields: [
|
||||
{ key: 'studentId', label: '学生', type: 'number', required: true },
|
||||
{ key: 'periodStart', label: '账期开始', type: 'date', required: true },
|
||||
{ key: 'periodEnd', label: '账期结束', type: 'date', required: true },
|
||||
{ key: 'totalAmount', label: '总金额', type: 'number', required: true },
|
||||
{ key: 'status', label: '状态', type: 'enum', enumFrom: 'bill.status' },
|
||||
field('studentId', '学生', 'number', { required: true }),
|
||||
field('periodStart', '账期开始', 'date', { required: true }),
|
||||
field('periodEnd', '账期结束', 'date', { required: true }),
|
||||
field('totalAmount', '总金额', 'number', { required: true }),
|
||||
field('status', '状态', 'enum', { enumFrom: 'bill.status' }),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'student', via: 'bill', requiredFor: ['bill'] },
|
||||
{ entityKey: 'occupancy', via: 'bill', requiredFor: ['bill'] },
|
||||
{ entityKey: 'deposit', via: 'deposit', requiredFor: ['deposit'] },
|
||||
relation('student', 'bill', ['bill']),
|
||||
relation('occupancy', 'bill', ['bill']),
|
||||
relation('deposit', 'deposit', ['deposit']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'deposit',
|
||||
name: '押金',
|
||||
description: '押金收取与退还记录,通常在账单确认后处理。',
|
||||
}),
|
||||
entity('deposit', '押金', '押金收取与退还记录,通常在账单确认后处理。', {
|
||||
searchTool: 'search_deposits',
|
||||
requiredPermissions: ['deposit:view'],
|
||||
fields: [
|
||||
{ key: 'studentId', label: '学生', type: 'number', required: true },
|
||||
{ key: 'amount', label: '金额', type: 'number', required: true },
|
||||
{ key: 'status', label: '状态', type: 'enum', enumFrom: 'deposit.status' },
|
||||
field('studentId', '学生', 'number', { required: true }),
|
||||
field('amount', '金额', 'number', { required: true }),
|
||||
field('status', '状态', 'enum', { enumFrom: 'deposit.status' }),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'student', via: 'deposit', requiredFor: ['deposit'] },
|
||||
{ entityKey: 'bill', via: 'deposit', requiredFor: ['deposit'] },
|
||||
relation('student', 'deposit', ['deposit']),
|
||||
relation('bill', 'deposit', ['deposit']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'classroom',
|
||||
name: '教室档案',
|
||||
description: '教室基础档案,租赁与教室日程的前置数据。',
|
||||
}),
|
||||
entity('classroom', '教室档案', '教室基础档案,租赁与教室日程的前置数据。', {
|
||||
searchTool: 'search_classrooms',
|
||||
requiredPermissions: ['classroom:view'],
|
||||
fields: [
|
||||
{ key: 'name', label: '教室名称', type: 'string', required: true },
|
||||
{ key: 'building', label: '楼栋', type: 'string' },
|
||||
{ key: 'capacity', label: '容量', type: 'number' },
|
||||
field('name', '教室名称', 'string', { required: true }),
|
||||
field('building', '楼栋', 'string'),
|
||||
field('capacity', '容量', 'number'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'rental', via: 'classroom_rental', requiredFor: ['rental'] },
|
||||
{ entityKey: 'schedule', via: 'class_schedule', requiredFor: ['schedule'] },
|
||||
relation('rental', 'classroom_rental', ['rental']),
|
||||
relation('schedule', 'class_schedule', ['schedule']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'organization',
|
||||
name: '组织/校区',
|
||||
description: '校区与组织归属,租赁双方与档案归属依赖组织。',
|
||||
}),
|
||||
entity('organization', '组织/校区', '校区与组织归属,租赁双方与档案归属依赖组织。', {
|
||||
requiredPermissions: ['organization:view'],
|
||||
fields: [
|
||||
{ key: 'name', label: '名称', type: 'string', required: true },
|
||||
{ key: 'code', label: '编码', type: 'string' },
|
||||
{ key: 'isHost', label: '是否本部', type: 'boolean' },
|
||||
field('name', '名称', 'string', { required: true }),
|
||||
field('code', '编码', 'string'),
|
||||
field('isHost', '是否本部', 'boolean'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'student', via: 'organization', requiredFor: ['profile'] },
|
||||
{ entityKey: 'rental', via: 'classroom_rental', requiredFor: ['rental'] },
|
||||
relation('student', 'organization', ['profile']),
|
||||
relation('rental', 'classroom_rental', ['rental']),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'rental',
|
||||
name: '教室租赁',
|
||||
description: '教室租赁订单与合同(合同字段在租赁记录上),依赖教室与组织。',
|
||||
}),
|
||||
entity('rental', '教室租赁', '教室租赁订单与合同(合同字段在租赁记录上),依赖教室与组织。', {
|
||||
searchTool: 'search_classroom_rentals',
|
||||
requiredPermissions: ['rental:view'],
|
||||
fields: [
|
||||
{ key: 'classroomId', label: '教室', type: 'number', required: true },
|
||||
{ key: 'lesseeOrganizationId', label: '承租方', type: 'number' },
|
||||
{ key: 'startDate', label: '开始日期', type: 'date', required: true },
|
||||
{ key: 'endDate', label: '结束日期', type: 'date', required: true },
|
||||
{ key: 'dailyRate', label: '日租金', type: 'number' },
|
||||
{ key: 'contractPath', label: '合同文件', type: 'string' },
|
||||
field('classroomId', '教室', 'number', { required: true }),
|
||||
field('lesseeOrganizationId', '承租方', 'number'),
|
||||
field('startDate', '开始日期', 'date', { required: true }),
|
||||
field('endDate', '结束日期', 'date', { required: true }),
|
||||
field('dailyRate', '日租金', 'number'),
|
||||
field('contractPath', '合同文件', 'string'),
|
||||
],
|
||||
relations: [
|
||||
{ entityKey: 'classroom', via: 'classroom_rental', requiredFor: ['rental'] },
|
||||
{ entityKey: 'organization', via: 'classroom_rental', requiredFor: ['rental'] },
|
||||
{ entityKey: 'schedule', via: 'class_schedule', requiredFor: ['schedule'] },
|
||||
relation('classroom', 'classroom_rental', ['rental']),
|
||||
relation('organization', 'classroom_rental', ['rental']),
|
||||
relation('schedule', 'class_schedule', ['schedule']),
|
||||
],
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
export const BUSINESS_WORKFLOWS: readonly BusinessWorkflow[] = [
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface BusinessEntityRelation {
|
||||
entityKey: string;
|
||||
via: string;
|
||||
/** 需要该关系已建立的工作流阶段 key。 */
|
||||
requiredFor: string[];
|
||||
requiredFor: readonly string[];
|
||||
}
|
||||
|
||||
export interface BusinessEntity {
|
||||
|
||||
Reference in New Issue
Block a user