feat: add content navigation practice assembly

This commit is contained in:
Codex
2026-06-21 23:04:39 +08:00
parent efce192844
commit c1159f8745
18 changed files with 2358 additions and 74 deletions

View File

@@ -14,6 +14,14 @@ const ids = {
region: '00000000-0000-0000-0000-000000000301',
subject: '00000000-0000-0000-0000-000000000501',
category: '00000000-0000-0000-0000-000000000601',
contentEntry: '00000000-0000-0000-0000-000000000611',
contentNodeCulture: '00000000-0000-0000-0000-000000000612',
contentNodeProfessional: '00000000-0000-0000-0000-000000000613',
contentNodeSchoolTarget: '00000000-0000-0000-0000-000000000614',
questionCollection: '00000000-0000-0000-0000-000000000615',
practiceBlueprintSequential: '00000000-0000-0000-0000-000000000616',
practiceBlueprintRandom: '00000000-0000-0000-0000-000000000617',
practiceBlueprintMock: '00000000-0000-0000-0000-000000000618',
questionBank: '00000000-0000-0000-0000-000000000400',
question: '00000000-0000-0000-0000-000000000401',
questionVersion: '00000000-0000-0000-0000-000000000402',
@@ -238,20 +246,235 @@ async function main() {
[ids.questionBank, tenantId, ids.region],
);
await client.query(
`
insert into public.content_entries (
id, tenant_id, region_id, legacy_id, entry_key, name, entry_type,
icon, route, description, visibility, layout_config, sort_order, is_active, created_by, updated_by
)
values (
$1, $2, $3, 'smoke-practice-entry', 'smoke-question-practice', '烟测刷题入口',
'question_practice', 'book-open', '/practice', '用于验证新内容导航和组卷链路',
'public', '{"tabs":["all","paper","chapter","type"]}'::jsonb, 1, true, $4, $4
)
on conflict (id)
do update set region_id = excluded.region_id,
name = excluded.name,
entry_key = excluded.entry_key,
entry_type = excluded.entry_type,
layout_config = excluded.layout_config,
is_active = true,
updated_at = now()
`,
[ids.contentEntry, tenantId, ids.region, ids.tenantAdminUser],
);
await client.query(
`
insert into public.content_nodes (
id, tenant_id, entry_id, region_id, parent_id, legacy_id, node_key,
name, node_type, marker_type, marker_config, path, depth, sort_order,
is_active, is_selectable, is_leaf, metadata, created_by, updated_by
)
values
(
$1, $2, $5, $6, null, 'smoke-culture-node', 'culture',
'文化课', 'category', 'exam_track', '{"intentKey":"culture"}'::jsonb,
'n_000000000000000000000000000000612'::ltree, 0, 1,
true, true, true, '{"businessMeaning":"公共课入口"}'::jsonb, $7, $7
),
(
$3, $2, $5, $6, null, 'smoke-professional-node', 'professional',
'专业课', 'category', 'exam_track', '{"intentKey":"professional"}'::jsonb,
'n_000000000000000000000000000000613'::ltree, 0, 2,
true, true, false, '{"businessMeaning":"院校自主命题入口"}'::jsonb, $7, $7
),
(
$4, $2, $5, $6, $3, 'smoke-school-target-node', 'professional-school-a',
'烟测学院专业课', 'school', 'school', '{"schoolName":"烟测学院","salesIntent":true}'::jsonb,
'n_000000000000000000000000000000613.n_000000000000000000000000000000614'::ltree, 1, 1,
true, true, true, '{"businessMeaning":"学生目标院校意向"}'::jsonb, $7, $7
)
on conflict (id)
do update set name = excluded.name,
parent_id = excluded.parent_id,
node_type = excluded.node_type,
marker_type = excluded.marker_type,
marker_config = excluded.marker_config,
path = excluded.path,
depth = excluded.depth,
is_leaf = excluded.is_leaf,
metadata = excluded.metadata,
updated_at = now()
`,
[
ids.contentNodeCulture,
tenantId,
ids.contentNodeProfessional,
ids.contentNodeSchoolTarget,
ids.contentEntry,
ids.region,
ids.tenantAdminUser,
],
);
await client.query(
`
insert into public.question_collections (
id, tenant_id, region_id, entry_id, node_id, subject_id, category_id,
question_bank_id, legacy_id, name, collection_type, source_type,
filters, question_count, total_score, duration_minutes, status,
sort_order, metadata, created_by, updated_by
)
values (
$1, $2, $3, $4, $5, $6, $7,
$8, 'smoke-collection', '烟测学院专业课题目列表', 'manual', 'manual_questions',
'{"tabs":["all","paper","chapter","type"]}'::jsonb, 0, 100, 120, 'active',
1, '{"business":"supports sequential random mock exam"}'::jsonb, $9, $9
)
on conflict (id)
do update set node_id = excluded.node_id,
subject_id = excluded.subject_id,
category_id = excluded.category_id,
question_bank_id = excluded.question_bank_id,
name = excluded.name,
collection_type = excluded.collection_type,
source_type = excluded.source_type,
filters = excluded.filters,
total_score = excluded.total_score,
duration_minutes = excluded.duration_minutes,
status = 'active',
updated_at = now()
`,
[
ids.questionCollection,
tenantId,
ids.region,
ids.contentEntry,
ids.contentNodeSchoolTarget,
ids.subject,
ids.category,
ids.questionBank,
ids.tenantAdminUser,
],
);
await client.query(
`
insert into public.questions (
id, tenant_id, question_bank_id, subject_id, category_id,
legacy_id, type, type_label, difficulty, status
entry_id, content_node_id, primary_collection_id,
legacy_id, type, type_label, difficulty, status, exam_markers
)
values (
$1, $2, $3, $4, $5, $6, $7, $8,
'smoke-question', 'choice', '单选题', 1, 'published',
'{"examTrack":"professional","school":"烟测学院"}'::jsonb
)
values ($1, $2, $3, $4, $5, 'smoke-question', 'choice', '单选题', 1, 'published')
on conflict (id)
do update set question_bank_id = excluded.question_bank_id,
subject_id = excluded.subject_id,
category_id = excluded.category_id,
entry_id = excluded.entry_id,
content_node_id = excluded.content_node_id,
primary_collection_id = excluded.primary_collection_id,
exam_markers = excluded.exam_markers,
updated_at = now()
`,
[ids.question, tenantId, ids.questionBank, ids.subject, ids.category],
[
ids.question,
tenantId,
ids.questionBank,
ids.subject,
ids.category,
ids.contentEntry,
ids.contentNodeSchoolTarget,
ids.questionCollection,
],
);
await client.query(
`
insert into public.question_collection_items (
tenant_id, collection_id, question_id, section_key, sort_order, score, required, metadata
)
values ($1, $2, $3, 'choice', 1, 2, true, '{"source":"smoke-seed"}'::jsonb)
on conflict (tenant_id, collection_id, question_id)
do update set section_key = excluded.section_key,
sort_order = excluded.sort_order,
score = excluded.score,
updated_at = now()
`,
[tenantId, ids.questionCollection, ids.question],
);
await client.query(
`
update public.question_collections
set question_count = (
select count(*)
from public.question_collection_items
where tenant_id = $1 and collection_id = $2
),
updated_at = now()
where tenant_id = $1 and id = $2
`,
[tenantId, ids.questionCollection],
);
await client.query(
`
insert into public.practice_blueprints (
id, tenant_id, region_id, entry_id, node_id, collection_id,
legacy_id, name, mode, assembly_type, question_limit,
duration_minutes, total_score, pass_score, sections, rules,
status, sort_order, created_by, updated_by
)
values
(
$1, $4, $5, $6, $7, $8,
'smoke-sequential-blueprint', '烟测顺序刷题', 'sequential', 'collection', 20,
null, null, null, '[]'::jsonb, '{"randomize":false}'::jsonb,
'active', 1, $9, $9
),
(
$2, $4, $5, $6, $7, $8,
'smoke-random-blueprint', '烟测随机刷题', 'random', 'collection', 20,
null, null, null, '[]'::jsonb, '{"randomize":true}'::jsonb,
'active', 2, $9, $9
),
(
$3, $4, $5, $6, $7, $8,
'smoke-mock-blueprint', '烟测全真模拟', 'mock_exam', 'collection', 10,
120, 100, 60,
'[{"key":"choice","title":"单选题","questionType":"choice","questionCount":10,"scoreEach":2}]'::jsonb,
'{"randomize":true,"showAnalysisAfterSubmit":false}'::jsonb,
'active', 3, $9, $9
)
on conflict (id)
do update set name = excluded.name,
mode = excluded.mode,
assembly_type = excluded.assembly_type,
question_limit = excluded.question_limit,
duration_minutes = excluded.duration_minutes,
total_score = excluded.total_score,
pass_score = excluded.pass_score,
sections = excluded.sections,
rules = excluded.rules,
status = 'active',
updated_at = now()
`,
[
ids.practiceBlueprintSequential,
ids.practiceBlueprintRandom,
ids.practiceBlueprintMock,
tenantId,
ids.region,
ids.contentEntry,
ids.contentNodeSchoolTarget,
ids.questionCollection,
ids.tenantAdminUser,
],
);
await client.query(