9fd503b42b
P0 — 答题体验优化: - 题序导航点:题目进度可视化,标记题目标记 - 标记回头检查: 点击🏷️按钮标记当前题,导航点变黄色 - 提交确认弹窗: 未答完时提交弹出确认对话框 P1 — 题库管理增强: - QuestionBankItem 新增 tags 字段(多标签过滤) - 新增 question_bank_templates 联表(题库跨模板复用) P2 — 考试配置增强: - AssessmentTemplate 新增字段: - attemptLimit (尝试次数限制) - scheduledStart/scheduledEnd (预约时段) - reviewMode (回顾模式: none/after_completion/per_question) - shuffleQuestions (每题随机排序) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
ManyToOne,
|
|
JoinColumn,
|
|
} from 'typeorm';
|
|
import { Tenant } from '../../tenant/tenant.entity';
|
|
import { KnowledgeBase } from '../../knowledge-base/knowledge-base.entity';
|
|
import { KnowledgeGroup } from '../../knowledge-group/knowledge-group.entity';
|
|
|
|
@Entity('assessment_templates')
|
|
export class AssessmentTemplate {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Column({ name: 'tenant_id', nullable: true })
|
|
tenantId: string;
|
|
|
|
@ManyToOne(() => Tenant, { nullable: true, onDelete: 'CASCADE' })
|
|
@JoinColumn({ name: 'tenant_id' })
|
|
tenant: Tenant;
|
|
|
|
@Column()
|
|
name: string;
|
|
|
|
@Column({ type: 'text', nullable: true })
|
|
description: string;
|
|
|
|
@Column({ type: 'simple-json', nullable: true })
|
|
keywords: string[];
|
|
|
|
@Column({ type: 'int', name: 'question_count', default: 5 })
|
|
questionCount: number;
|
|
|
|
@Column({
|
|
type: 'simple-json',
|
|
name: 'difficulty_distribution',
|
|
nullable: true,
|
|
})
|
|
difficultyDistribution: {
|
|
standard: number;
|
|
advanced: number;
|
|
specialist: number;
|
|
};
|
|
|
|
@Column({ type: 'varchar', default: 'technical' })
|
|
style: string;
|
|
|
|
@Column({ name: 'knowledge_base_id', nullable: true })
|
|
knowledgeBaseId: string | null;
|
|
|
|
@ManyToOne(() => KnowledgeBase, { nullable: true })
|
|
@JoinColumn({ name: 'knowledge_base_id' })
|
|
knowledgeBase: KnowledgeBase;
|
|
|
|
@Column({ name: 'knowledge_group_id', nullable: true })
|
|
knowledgeGroupId: string | null;
|
|
|
|
@ManyToOne(() => KnowledgeGroup, { nullable: true })
|
|
@JoinColumn({ name: 'knowledge_group_id' })
|
|
knowledgeGroup: KnowledgeGroup;
|
|
|
|
@Column({ type: 'simple-json', name: 'dimensions', nullable: true })
|
|
dimensions: Array<{ name: string; label: string; weight: number }>;
|
|
|
|
@Column({ type: 'boolean', name: 'is_active', default: true })
|
|
isActive: boolean;
|
|
|
|
@Column({ type: 'int', default: 1 })
|
|
version: number;
|
|
|
|
@Column({ name: 'created_by', nullable: true })
|
|
createdBy: string;
|
|
|
|
@Column({ type: 'simple-json', name: 'linked_group_ids', nullable: true })
|
|
linkedGroupIds: string[];
|
|
|
|
@Column({ type: 'simple-json', name: 'weight_config', nullable: true })
|
|
weightConfig: {
|
|
prompt: number;
|
|
other: number;
|
|
};
|
|
|
|
@Column({ type: 'simple-json', name: 'difficulty_config', nullable: true })
|
|
difficultyConfig: {
|
|
standard: number;
|
|
advanced: number;
|
|
specialist: number;
|
|
};
|
|
|
|
@Column({ type: 'int', name: 'question_count_min', default: 8 })
|
|
questionCountMin: number;
|
|
|
|
@Column({ type: 'int', name: 'question_count_max', default: 10 })
|
|
questionCountMax: number;
|
|
|
|
@Column({ type: 'int', name: 'passing_score', default: 60 })
|
|
passingScore: number;
|
|
|
|
@Column({ type: 'int', name: 'total_time_limit', default: 1800 })
|
|
totalTimeLimit: number;
|
|
|
|
@Column({ type: 'int', name: 'per_question_time_limit', default: 300 })
|
|
perQuestionTimeLimit: number;
|
|
|
|
/** P2: Max attempts (0=unlimited) */
|
|
@Column({ type: 'int', name: 'attempt_limit', default: 1 })
|
|
attemptLimit: number;
|
|
|
|
/** P2: Scheduled window start (null=anytime) */
|
|
@Column({ type: 'text', name: 'scheduled_start', nullable: true })
|
|
scheduledStart: string | null;
|
|
|
|
/** P2: Scheduled window end (null=anytime) */
|
|
@Column({ type: 'text', name: 'scheduled_end', nullable: true })
|
|
scheduledEnd: string | null;
|
|
|
|
/** P2: Review mode: 'none' | 'after_completion' | 'per_question' */
|
|
@Column({ type: 'varchar', name: 'review_mode', default: 'none', length: 20 })
|
|
reviewMode: string;
|
|
|
|
/** P2: Shuffle questions per candidate */
|
|
@Column({ type: 'boolean', name: 'shuffle_questions', default: true })
|
|
shuffleQuestions: boolean;
|
|
|
|
@CreateDateColumn({ name: 'created_at' })
|
|
createdAt: Date;
|
|
|
|
@UpdateDateColumn({ name: 'updated_at' })
|
|
updatedAt: Date;
|
|
}
|