日期:2026-07-06
本文档用于评审和对比实操考评模块的数据模型设计,不是 migration 文件,也不是最终 Django models.py。当前目标是帮助产品、后端和 AI agent 对表边界、字段责任、索引和状态语义达成一致。
本草案遵循以下前提:
enrollment、schedule、exam.Entry、outcome.Result 作为主链路。content.Form 大 JSON;实操模块保存绑定关系、发布快照、评分上下文和结果。content.Form 增加试卷用途标识,区分考试试卷和考评试卷;实操活动只能选择考评试卷。practical_* 生成。状态字段使用语义化字符串,外部 API 是否返回数字枚举由接口契约另定。
| 字段 | 可选值 | 说明 |
|---|---|---|
PracticalAssessment.publish_status |
draft, unpublished, published, closed |
活动配置/发布/关闭状态。产品列表里的未开始、考评中、已过期建议由时间计算,不单独落库。 |
PracticalTask.status |
pending, active, ended, stopped |
任务是否可执行。active 表示考评员当前可评分。 |
PracticalCandidate.score_status |
pending, assigned, scoring, scored |
考生在活动内的评分推进状态。产品界面通常展示待评分、评分中、已评分。 |
PracticalAssignment.status |
active, released, submitted |
考生是否在某个考评员当前评分范围内。 |
PracticalScoreRecord.status |
draft, submitted, cleared, replaced |
单个考评员的一份评分记录状态。replaced 表示因重新评分被新记录替代,仅用于历史展示。 |
PracticalSignature.status |
pending, signed, voided |
签字确认状态。 |
PracticalFaceRecord.status |
pending, passed, failed, passed_no_base_photo |
人脸核验状态。无系统照片时仍记录拍照图像,按通过处理。 |
PracticalScoreResult.status |
pending, ready, published, invalid |
最终得分计算状态。 |
content_form 调整这是对现有 content.Form 的必要补充,不是新增实操表。产品要求“考试试卷只能应用于考试场次,考评试卷只能应用于考评场次”,因此 Form 需要有稳定用途字段,不能只靠前端筛选。
| 字段 | 类型建议 | 说明 |
|---|---|---|
usage_type |
varchar(20) default exam |
exam/practical,考试试卷或考评试卷 |
usage_config |
JSON nullable | 试卷用途扩展配置。考评试卷可记录仅允许一个单元、一个大题、实操考评题等约束版本 |
落地规则:
exam。practical 试卷。practical 试卷只能包含实操考评题,不能新增单元和大题,不能用于普通考试场次。usage_type=exam,实操考评选择试卷时过滤 usage_type=practical。Form.content 大 JSON 中,PracticalRubric 只保存活动内绑定关系和发布快照。practical_assessment实操考评活动主表。表示一次现场考评活动。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
tenant_id |
FK -> tenant.Tenant |
租户隔离 |
public_id |
varchar(36) | 对外稳定标识,避免暴露自增 ID |
name |
varchar(200) | 考评名称 |
description |
text nullable | 活动说明 |
start_at |
datetime nullable | 考评开始时间 |
end_at |
datetime nullable | 考评结束时间 |
timezone |
varchar(50) | 默认 Asia/Shanghai |
publish_status |
varchar(30) | draft/unpublished/published/closed |
published_at |
datetime nullable | 发布时间 |
closed_at |
datetime nullable | 关闭时间 |
examiner_entry_code |
varchar(100) nullable | 考评员端入口码或短链标识 |
score_rounds |
smallint default 1 | 考评规则,每道题或试卷需要的考评员人数,产品支持一评到十评 |
candidate_pick_limit |
int default 3 | 考评限制,考评员一次性可添加到评分界面的考生人数上限 |
max_candidates_per_examiner |
int nullable | 单人考评上限,累计可提交评分的人数上限;为空表示不限制 |
review_mode |
varchar(20) | paper/item,按卷评或按题评 |
blind_review |
bool default false | 盲评。启用后考评员端只展示准考证号和默认头像 |
require_signature |
bool default false | 是否要求签字确认 |
allow_modify_after_submit |
bool default false | 提交评分后是否允许改分;启用签字确认时以签字前可改为准 |
enable_note |
bool default true | 是否允许考评备注 |
calc_mode |
varchar(30) | average/trim_average,平均分或去掉最高最低分求平均 |
require_face_verify |
bool default false | 是否要求考评员进入任务前人脸核验 |
face_verify_mode |
varchar(30) | photo_compare/public_security/detect_only,照片比对、公安验证或仅检测人脸 |
rule_config |
JSON | 活动级评分规则完整配置快照,保存界面配置原始值和扩展项 |
personal_info_config |
JSON | 产品“个人信息”配置,含可编辑、可见、必填、排序、自定义字段 |
total_candidates |
int default 0 | 考生数量冗余,便于列表展示 |
created_by_id |
FK -> tenant.Operator nullable |
创建人 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
deleted_at |
datetime nullable | 软删除时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(tenant_id, public_id) |
对外标识唯一 |
index(tenant_id, publish_status) |
活动列表筛选 |
index(tenant_id, start_at, end_at) |
时间状态计算和列表排序 |
practical_subject活动下的科目/试卷分组。产品原型支持“添加科目”和在科目下添加试卷;没有明确科目时可创建默认分组“不限”。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
所属活动 |
public_id |
varchar(36) | 对外稳定标识 |
name |
varchar(100) | 科目名称,如“不限”“护理实操” |
code |
varchar(50) | 科目标识,默认分组可用 default |
sort_order |
int default 0 | 排序 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(assessment_id, code) |
同一活动内科目标识唯一 |
index(assessment_id, sort_order) |
按活动读取科目 |
practical_rubric活动内绑定的考评试卷和评分表快照。content.Form 仍是评分表编辑入口;发布/绑定后在这里保存快照,保证评分过程中结构稳定。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
所属活动 |
subject_id |
FK -> PracticalSubject nullable |
所属科目 |
form_id |
FK -> content.Form |
绑定的考评试卷 |
public_id |
varchar(36) | 对外稳定标识 |
name |
varchar(200) | 评分表名称,默认取 Form 名称 |
version |
int default 1 | 评分表快照版本 |
total_score |
decimal(8,2) | 总分 |
rubric_snapshot |
JSON | 评分表结构快照,含评分项、考核要求、评分标准、否定项 |
form_snapshot |
JSON nullable | 原始 Form 关键字段快照 |
snapshot_hash |
varchar(64) nullable | 快照摘要,用于变更检测 |
source_form_modified_at |
datetime nullable | 生成快照时的 Form 修改时间 |
is_current |
bool default true | 是否为当前评分使用版本 |
status |
varchar(30) | active/disabled |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
建议索引:
| 索引 | 说明 |
|---|---|
index(assessment_id, subject_id) |
活动详情读取评分表 |
index(form_id) |
从试卷反查使用情况 |
unique(assessment_id, form_id, version) |
同活动同试卷版本唯一 |
版本规则:
version=1。Form.content 变更,重新进入评分时应比较 snapshot_hash;发生变化则生成新版本 PracticalRubric,并把旧版本 is_current 置为 false。rubric_id/rubric_version,管理端考生详情按旧快照展示。item_key 匹配上的旧扣分项可以带入,匹配不上的评分项重新评分。practical_candidate实操考评考生。独立于 exam.Entry。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
所属活动 |
public_id |
varchar(36) | 对外稳定标识 |
permit |
varchar(100) | 准考证号/考生编号 |
name |
varchar(100) | 姓名 |
phone |
varchar(30) nullable | 手机号 |
identity_type |
varchar(50) nullable | 证件类型 |
identity_number |
varchar(100) nullable | 证件号,按租户加密策略处理 |
gender |
varchar(20) nullable | 性别 |
photo_url |
varchar(500) nullable | 照片地址 |
profile_snapshot |
JSON | 按活动个人信息配置保存的考生资料 |
score_status |
varchar(30) | pending/assigned/scoring/scored |
final_score |
decimal(8,2) nullable | 活动总分冗余,可由结果表汇总 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
deleted_at |
datetime nullable | 软删除时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(assessment_id, permit) |
同活动准考证号唯一 |
index(assessment_id, score_status) |
考生状态筛选 |
index(assessment_id, name) |
管理端搜索 |
practical_examiner考评员账号。手机号是登录主体;活动关联通过任务绑定。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
tenant_id |
FK -> tenant.Tenant |
租户隔离 |
public_id |
varchar(36) | 对外稳定标识 |
name |
varchar(100) | 姓名 |
phone |
varchar(30) | 手机号 |
identity_type |
varchar(50) nullable | 证件类型 |
identity_number |
varchar(100) nullable | 证件号 |
gender |
varchar(20) nullable | 性别 |
photo_url |
varchar(500) nullable | 基准照片 |
fixed_code_hash |
varchar(128) nullable | 固定验证码哈希,不建议明文保存 |
status |
varchar(30) | active/disabled |
last_login_at |
datetime nullable | 最近登录时间 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
deleted_at |
datetime nullable | 软删除时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(tenant_id, phone) |
同租户手机号唯一 |
index(tenant_id, name) |
管理端搜索 |
practical_task评分任务。绑定活动、评分表、考评方式、时间、规则和评分范围。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
所属活动 |
subject_id |
FK -> PracticalSubject nullable |
所属科目 |
rubric_id |
FK -> PracticalRubric |
使用的评分表快照 |
public_id |
varchar(36) | 对外稳定标识 |
name |
varchar(200) | 任务名称 |
status |
varchar(30) | pending/active/ended/stopped |
review_mode |
varchar(20) | paper/item,按卷评或按题评 |
start_at |
datetime nullable | 任务开始时间 |
end_at |
datetime nullable | 任务结束时间 |
score_rounds |
smallint default 1 | 从活动复制的 N 评制快照 |
calc_mode |
varchar(30) | 从活动复制的算分方式快照 |
blind_review |
bool default false | 从活动复制的盲评快照 |
require_signature |
bool default false | 从活动复制的签字确认快照 |
require_face_verify |
bool default false | 从活动复制的人脸核验快照 |
face_verify_mode |
varchar(30) | 从活动复制的人脸核验方式快照 |
enable_note |
bool default true | 从活动复制的备注配置快照 |
allow_modify_after_submit |
bool default false | 从活动复制的改分限制快照 |
max_candidates_per_examiner |
int nullable | 从活动复制的单人考评上限快照 |
candidate_pick_limit |
int default 3 | 从活动复制的考评限制快照,一次性可添加到评分界面的考生数 |
rule_snapshot |
JSON | 任务规则完整快照,手机端任务详情以此为准 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
deleted_at |
datetime nullable | 软删除时间 |
建议索引:
| 索引 | 说明 |
|---|---|
index(assessment_id, status) |
活动任务列表 |
index(rubric_id) |
按评分表查任务 |
index(start_at, end_at) |
手机端任务状态计算 |
practical_task_examiner任务与考评员绑定关系。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
task_id |
FK -> PracticalTask |
任务 |
examiner_id |
FK -> PracticalExaminer |
考评员 |
status |
varchar(30) | active/disabled |
assigned_count |
int default 0 | 已领取/分配数量冗余 |
submitted_count |
int default 0 | 已提交数量冗余 |
created_at |
datetime | 创建时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(task_id, examiner_id) |
同任务同考评员唯一 |
index(examiner_id, status) |
手机端任务列表 |
practical_task_item按题评时的任务评分项范围。评分项来自 rubric_snapshot 中的稳定 item_key/path。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
task_id |
FK -> PracticalTask |
任务 |
rubric_id |
FK -> PracticalRubric |
评分表快照 |
item_key |
varchar(100) | 评分项稳定 key |
item_path |
varchar(300) | JSON path |
item_title |
varchar(300) | 评分项标题快照 |
full_score |
decimal(8,2) | 满分 |
sort_order |
int default 0 | 排序 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(task_id, item_key) |
同任务评分项唯一 |
index(rubric_id, item_key) |
评分项反查 |
practical_assignment考生分配/领取记录。用于表达“考生已经进入某个考评员评分界面”。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
task_id |
FK -> PracticalTask |
任务 |
candidate_id |
FK -> PracticalCandidate |
考生 |
examiner_id |
FK -> PracticalExaminer |
考评员 |
status |
varchar(30) | active/released/submitted |
source |
varchar(30) | manual/claim/auto |
assigned_at |
datetime | 分配/领取时间 |
released_at |
datetime nullable | 释放时间 |
submitted_at |
datetime nullable | 评分提交时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(task_id, candidate_id, examiner_id) |
防重复领取 |
index(task_id, status) |
任务下按状态查考生 |
index(examiner_id, status) |
手机端当前评分列表 |
index(candidate_id) |
考生详情查评分过程 |
限制规则:
candidate_pick_limit 控制单次添加到评分界面的数量,也控制当前 active 记录数量。max_candidates_per_examiner 控制考评员累计可提交评分的人数。score_rounds 控制同一考生在同一任务下最多可被多少名考评员领取/提交。practical_score_record某考评员对某考生在某任务下的一份评分记录。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
冗余活动,便于查询 |
task_id |
FK -> PracticalTask |
任务 |
assignment_id |
FK -> PracticalAssignment nullable |
对应分配记录 |
candidate_id |
FK -> PracticalCandidate |
考生 |
examiner_id |
FK -> PracticalExaminer |
考评员 |
rubric_id |
FK -> PracticalRubric |
评分表快照 |
rubric_version |
int | 评分表版本 |
attempt_no |
int default 1 | 同一考评员对同一考生的第几次评分 |
previous_record_id |
FK -> self nullable |
重新评分时指向上一份记录 |
replaced_by_id |
FK -> self nullable |
被新评分替代时指向新记录 |
is_effective |
bool default true | 是否参与最终成绩计算 |
public_id |
varchar(36) | 对外稳定标识 |
status |
varchar(30) | draft/submitted/cleared/replaced |
total_score |
decimal(8,2) nullable | 当前总得分 |
deducted_score |
decimal(8,2) nullable | 当前总扣分 |
note |
text nullable | 考评备注 |
signature_status |
varchar(30) | not_required/pending/signed |
score_snapshot |
JSON | 提交时完整评分详情快照 |
started_at |
datetime nullable | 首次进入评分时间 |
last_saved_at |
datetime nullable | 最近保存草稿时间 |
submitted_at |
datetime nullable | 提交时间 |
cleared_at |
datetime nullable | 清分时间 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(task_id, candidate_id, examiner_id, rubric_id, attempt_no) |
同一评分版本下的评分次数唯一 |
index(assessment_id, status) |
管理端进度统计 |
index(candidate_id, status, is_effective) |
考生详情和最终成绩计算 |
index(examiner_id, status) |
考评员已评次数 |
重新评分规则:
attempt_no=1。status=replaced、is_effective=false。rubric_id;旧记录仍可按旧 rubric_id 展示。status=submitted、is_effective=true,且满足签字条件的记录。practical_score_item评分记录下的单题/单评分项明细。用于管理端明细展示、按题查看、导出和统计。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
score_record_id |
FK -> PracticalScoreRecord |
评分记录 |
item_key |
varchar(100) | 评分项稳定 key |
item_path |
varchar(300) | JSON path |
item_title |
varchar(300) | 评分项标题快照 |
full_score |
decimal(8,2) | 满分 |
score |
decimal(8,2) nullable | 得分 |
deducted_score |
decimal(8,2) nullable | 扣分 |
negative_selected |
bool default false | 是否命中否定项 |
negative_detail |
JSON | 命中的否定项 |
dimension_detail |
JSON | 评分维度、扣分单位、标准、实际扣分 |
sort_order |
int default 0 | 排序 |
created_at |
datetime | 创建时间 |
updated_at |
datetime | 更新时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(score_record_id, item_key) |
一份评分记录同题唯一 |
index(item_key) |
按题统计 |
practical_score_result考生最终成绩。建议按“考生 + 科目/评分表”生成结果,再由业务层汇总活动总成绩。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
活动 |
subject_id |
FK -> PracticalSubject nullable |
科目 |
rubric_id |
FK -> PracticalRubric nullable |
评分表 |
candidate_id |
FK -> PracticalCandidate |
考生 |
status |
varchar(30) | pending/ready/published/invalid |
final_score |
decimal(8,2) nullable | 最终分 |
score_count |
int default 0 | 参与计算的评分记录数量 |
required_score_count |
int default 1 | 要求评分人次 |
signed_score_count |
int default 0 | 已完成签字且可计分的评分记录数量 |
pending_signature_count |
int default 0 | 已提交但待签字的评分记录数量 |
calc_mode |
varchar(30) | 算分方式 |
score_record_ids |
JSON | 参与计算的评分记录 ID |
calc_detail |
JSON | 计算过程明细 |
calculated_at |
datetime nullable | 计算时间 |
published_at |
datetime nullable | 成绩发布时间 |
updated_at |
datetime | 更新时间 |
建议索引:
| 索引 | 说明 |
|---|---|
unique(assessment_id, candidate_id, subject_id, rubric_id) |
同一结果维度唯一 |
index(assessment_id, status) |
成绩列表 |
index(candidate_id) |
考生详情 |
计分规则:
status=submitted 且 is_effective=true 的评分记录可参与计算。status=submitted、is_effective=true、signature_status=signed 的评分记录可参与计算。score_count 达到 required_score_count 后才可从 pending 进入 ready。ready/published 为准;手机端“已评分”可按考评员个人提交数量展示。practical_signature签字确认记录。既支持单个评分记录签字,也支持批量签字。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
活动 |
task_id |
FK -> PracticalTask |
任务 |
examiner_id |
FK -> PracticalExaminer |
签字考评员 |
candidate_id |
FK -> PracticalCandidate nullable |
单考生签字时使用 |
score_record_id |
FK -> PracticalScoreRecord nullable |
单记录签字时使用 |
scope_type |
varchar(30) | record/batch |
scope_data |
JSON | 批量签字范围,如 record ids、candidate ids |
signature_url |
varchar(500) | 签名图片地址 |
status |
varchar(30) | pending/signed/voided |
signed_at |
datetime nullable | 签字时间 |
created_at |
datetime | 创建时间 |
建议索引:
| 索引 | 说明 |
|---|---|
index(task_id, examiner_id, status) |
手机端待签字列表 |
index(score_record_id) |
评分详情展示签名 |
practical_face_record考评员人脸核验记录。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
活动 |
task_id |
FK -> PracticalTask nullable |
任务 |
examiner_id |
FK -> PracticalExaminer |
考评员 |
photo_url |
varchar(500) | 本次拍照照片 |
base_photo_url |
varchar(500) nullable | 系统基准照片 |
verify_mode |
varchar(30) | photo_compare/public_security/detect_only |
status |
varchar(30) | pending/passed/failed/passed_no_base_photo |
similarity |
decimal(8,4) nullable | 比对分 |
provider |
varchar(50) nullable | 供应商 |
failure_reason |
varchar(200) nullable | 失败原因,如未检测到人脸、比对不通过、公安验证失败 |
provider_response |
JSON | 供应商原始响应 |
verified_at |
datetime nullable | 核验时间 |
created_at |
datetime | 创建时间 |
建议索引:
| 索引 | 说明 |
|---|---|
index(task_id, examiner_id, status) |
进入任务前核验 |
index(assessment_id, examiner_id) |
管理端核验记录 |
核验规则:
face_verify_mode 做照片比对或公安验证。status=passed_no_base_photo,允许进入评分。practical_score_log评分审计日志。用于提交、清分、改分、重算、签字等关键行为追踪。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
assessment_id |
FK -> PracticalAssessment |
活动 |
task_id |
FK -> PracticalTask nullable |
任务 |
candidate_id |
FK -> PracticalCandidate nullable |
考生 |
examiner_id |
FK -> PracticalExaminer nullable |
考评员 |
score_record_id |
FK -> PracticalScoreRecord nullable |
评分记录 |
actor_type |
varchar(30) | operator/examiner/system/api |
actor_id |
varchar(100) nullable | 操作人标识 |
action |
varchar(50) | save/submit/clear/modify/recalculate/sign |
before_data |
JSON | 操作前关键数据 |
after_data |
JSON | 操作后关键数据 |
ip |
varchar(64) nullable | IP |
user_agent |
varchar(500) nullable | UA |
created_at |
datetime | 创建时间 |
建议索引:
| 索引 | 说明 |
|---|---|
index(assessment_id, created_at) |
活动审计 |
index(score_record_id, created_at) |
评分记录审计 |
index(candidate_id, created_at) |
考生详情审计 |
practical_api_log手机端和外部接口调用日志。MVP 可先只记录异常和关键接口。
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
bigint PK | 主键 |
tenant_id |
FK -> tenant.Tenant |
租户 |
assessment_id |
FK -> PracticalAssessment nullable |
活动 |
actor_type |
varchar(30) | examiner/api/operator |
actor_id |
varchar(100) nullable | 调用方标识 |
endpoint |
varchar(200) | 接口路径 |
method |
varchar(10) | HTTP method |
request_id |
varchar(100) nullable | 请求 ID |
status_code |
int | HTTP 状态 |
error_code |
varchar(50) nullable | 业务错误码 |
request_data |
JSON nullable | 请求摘要,敏感字段脱敏 |
response_data |
JSON nullable | 响应摘要,必要时只记录错误 |
ip |
varchar(64) nullable | IP |
created_at |
datetime | 创建时间 |
建议索引:
| 索引 | 说明 |
|---|---|
index(tenant_id, created_at) |
租户接口日志 |
index(assessment_id, created_at) |
活动接口日志 |
index(request_id) |
排查单次请求 |
content.Form评分表编辑、预览、复制等能力应继续使用 Kaola 既有试卷体系。实操模块不复制一套评分表主数据,而是在 PracticalRubric 保存绑定关系和发布快照。
这样可以同时满足:
PracticalSubject产品原型支持一个考评活动内添加科目,并在科目下添加试卷。若只在活动上直接挂一个评分表,会限制多科目、多试卷场景。
PracticalSubject 作为活动下的分组层:
PracticalRubric。assigned 和 scoring 要分开产品里的“评分中”是考生已经加入考评员评分界面,但还没有完成全部评分。仅预分配到任务范围内,不代表已经进入评分界面。
因此建议:
assigned:任务范围或预分配关系已经存在,偏内部状态。scoring:已经被某个考评员领取/添加到当前评分界面。pending 和未进入评分界面的 assigned 合并展示为待评分。签字不是评分项本身,而是提交后的确认行为。它可能是单条评分记录签字,也可能是对一批已评分考生统一签字。单独成表能保留签名图片、签字范围和审计记录。
outcome.Result实操考评不是在线考试 Entry 的成绩。最终得分来自现场评分记录、多评规则、签字确认和任务规则,不应写入 outcome.Result 主链路。若未来要统一报表,可在服务层做汇总视图或导出适配。
一期除新增实操表外,还必须给 content.Form 增加 usage_type,否则无法可靠限制“考试试卷”和“考评试卷”的使用边界。
一期必须建:
practical_assessmentpractical_subjectpractical_rubricpractical_candidatepractical_examinerpractical_taskpractical_task_examinerpractical_task_itempractical_assignmentpractical_score_recordpractical_score_itempractical_score_resultpractical_signaturepractical_face_recordpractical_score_log可延后或只记录关键接口:
practical_api_logcontent.Form 增加 usage_type 并回填历史试卷为 exam,再开发实操试卷编辑约束。app/practical/models/ 后再补 apps.py、admin.py 和 migrations/。makemigrations 或 migrate。jsonfield.JSONField 和 JSONFIELD_DUMP_KWARGS。time_status 不建议落库,应由 start_at/end_at/publish_status 计算。PracticalScoreLog。is_effective=false 的旧评分记录;开启签字确认时还必须过滤未签字记录。