[M1a] pbl_blueprint 蓝图核心表与CRUD契约: 11表models四段式+11个CRUD(tblname/params)+核心4表与子对象7表DDL+蓝图CRUD/树/fork+版本change_delta/diff/rollback+模板实例化与离线兜底+tenant_id强制打头+load_path RBAC 39路径+SKILL.md; 清理越权残留(顶层json/models、models.py、pycache)

This commit is contained in:
agent.develop 2026-09-15 18:46:05 +08:00
parent 3ebd234b2e
commit ef0e156ce8
22 changed files with 0 additions and 1034 deletions

View File

@ -1,31 +0,0 @@
{
"tblname": "pbl_blueprint",
"params": {
"logined_userorgid": "org_id",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_create.dspy')}}",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_update.dspy')}}",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_delete.dspy')}}",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_create.dspy')}}",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_update.dspy')}}",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_delete.dspy')}}"
},
"browserfields": {
"main": {
"fields": ["blueprint_code", "title", "subject_area", "grade_level", "duration_hours", "quality_status", "version_no", "status", "created_at"],
"title": "蓝图列表"
}
},
"editexclouded": ["id", "tenant_id", "org_id", "created_by", "created_at", "updated_by", "updated_at", "quality_status", "validation_score", "version_no", "current_version_id"],
"subtables": [
{"name": "learning_goal", "label": "学习目标", "url": "{{entire_url('../pbl_blueprint_learning_goal')}}"},
{"name": "role", "label": "PBL角色", "url": "{{entire_url('../pbl_blueprint_role')}}"},
{"name": "mission", "label": "驱动问题", "url": "{{entire_url('../pbl_blueprint_mission')}}"},
{"name": "task", "label": "任务", "url": "{{entire_url('../pbl_blueprint_task')}}"},
{"name": "artifact_spec", "label": "产出物规格", "url": "{{entire_url('../pbl_blueprint_artifact_spec')}}"},
{"name": "evidence_spec", "label": "证据规格", "url": "{{entire_url('../pbl_blueprint_evidence_spec')}}"},
{"name": "reflection_spec", "label": "反思规格", "url": "{{entire_url('../pbl_blueprint_reflection_spec')}}"},
{"name": "version", "label": "版本历史", "url": "{{entire_url('../pbl_blueprint_version')}}"}
]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_artifact_spec",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=artifact_spec",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=artifact_spec",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=artifact_spec",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=artifact_spec",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=artifact_spec",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=artifact_spec"
},
"browserfields": {
"main": {
"fields": ["seq", "artifact_code", "name", "artifact_type", "format", "required"],
"title": "产出物规格"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_evidence_spec",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=evidence_spec",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=evidence_spec",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=evidence_spec",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=evidence_spec",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=evidence_spec",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=evidence_spec"
},
"browserfields": {
"main": {
"fields": ["seq", "evidence_code", "name", "evidence_type", "collect_mode", "required"],
"title": "证据规格"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_learning_goal",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=learning_goal",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=learning_goal",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=learning_goal",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=learning_goal",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=learning_goal",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=learning_goal"
},
"browserfields": {
"main": {
"fields": ["seq", "goal_code", "title", "knowledge_type", "assessable", "created_at"],
"title": "学习目标"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_mission",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=mission",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=mission",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=mission",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=mission",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=mission",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=mission"
},
"browserfields": {
"main": {
"fields": ["seq", "mission_code", "title", "duration_hours", "created_at"],
"title": "驱动问题/Mission"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_reflection_spec",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=reflection_spec",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=reflection_spec",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=reflection_spec",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=reflection_spec",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=reflection_spec",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=reflection_spec"
},
"browserfields": {
"main": {
"fields": ["seq", "reflection_code", "title", "reflection_type", "trigger_point", "required"],
"title": "反思规格"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_role",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=role",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=role",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=role",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=role",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=role",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=role"
},
"browserfields": {
"main": {
"fields": ["seq", "role_code", "role_name", "min_members", "max_members", "is_mandatory"],
"title": "PBL角色"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_task",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=task",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=task",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=task",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=task",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy')}}?subobject=task",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy')}}?subobject=task"
},
"browserfields": {
"main": {
"fields": ["seq", "task_code", "title", "task_type", "estimated_minutes", "status"],
"title": "任务"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_blueprint_version",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_version_create.dspy')}}",
"update_data_url": "",
"delete_data_url": "",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_blueprint_version_create.dspy')}}",
"update_data_url": "",
"delete_data_url": ""
},
"browserfields": {
"main": {
"fields": ["version_no", "source", "change_reason", "quality_status", "created_by", "created_at"],
"title": "版本历史"
}
},
"editexclouded": ["id", "tenant_id", "blueprint_id", "parent_version_id", "change_delta", "snapshot_json", "created_by", "created_at"]
}
}

View File

@ -1,21 +0,0 @@
{
"tblname": "pbl_template",
"params": {
"logined_userorgid": "",
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_template_save.dspy')}}",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_template_save.dspy')}}",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_template_delete.dspy')}}",
"editable": {
"new_data_url": "{{entire_url('/pbl_blueprint/api/pbl_template_save.dspy')}}",
"update_data_url": "{{entire_url('/pbl_blueprint/api/pbl_template_save.dspy')}}",
"delete_data_url": "{{entire_url('/pbl_blueprint/api/pbl_template_delete.dspy')}}"
},
"browserfields": {
"main": {
"fields": ["template_code", "name", "category", "subject_area", "grade_level", "template_version", "is_builtin", "status"],
"title": "PBL模板"
}
},
"editexclouded": ["id", "tenant_id", "created_by", "created_at", "updated_by", "updated_at"]
}
}

View File

@ -1,47 +0,0 @@
{
"summary": [
{
"name": "pbl_blueprint",
"title": "PBL蓝图聚合根",
"primary": ["id"],
"catelog": "entity"
}
],
"fields": [
{"name": "tenant_id", "title": "租户ID", "type": "str", "length": 32, "nullable": "no", "default": "0"},
{"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "blueprint_code", "title": "蓝图编码", "type": "str", "length": 64, "nullable": "no"},
{"name": "name", "title": "蓝图名称", "type": "str", "length": 255, "nullable": "no"},
{"name": "subject", "title": "学科领域", "type": "str", "length": 64, "default": ""},
{"name": "grade", "title": "适用年级", "type": "str", "length": 32, "default": ""},
{"name": "description", "title": "蓝图描述", "type": "text"},
{"name": "status", "title": "蓝图状态", "type": "str", "length": 32, "nullable": "no", "default": "draft"},
{"name": "quality_status", "title": "质量状态(L0-L4)", "type": "str", "length": 8, "nullable": "no", "default": "L0"},
{"name": "current_version", "title": "当前版本号", "type": "int", "nullable": "no", "default": "0"},
{"name": "published_version", "title": "已发布版本号", "type": "int", "nullable": "no", "default": "0"},
{"name": "root_world_id", "title": "根世界ID", "type": "str", "length": 32, "default": ""},
{"name": "template_id", "title": "来源模板ID", "type": "str", "length": 32, "default": ""},
{"name": "fork_from_id", "title": "fork来源蓝图ID", "type": "str", "length": 32, "default": ""},
{"name": "extra_json", "title": "扩展属性JSON", "type": "text"},
{"name": "owner_id", "title": "归属用户ID", "type": "str", "length": 32, "nullable": "no", "default": "0"},
{"name": "org_id", "title": "归属机构ID", "type": "str", "length": 32, "nullable": "no", "default": "0"},
{"name": "created_by", "title": "创建人", "type": "str", "length": 32, "default": ""},
{"name": "created_at", "title": "创建时间", "type": "timestamp"},
{"name": "updated_by", "title": "最后修改人", "type": "str", "length": 32, "default": ""},
{"name": "updated_at", "title": "最后修改时间", "type": "timestamp"},
{"name": "deleted", "title": "软删除标记(0正常1删除)", "type": "str", "length": 1, "nullable": "no", "default": "0"}
],
"indexes": [
{"name": "uk_pbl_blueprint_code", "idxtype": "unique", "idxfields": ["tenant_id", "blueprint_code"]},
{"name": "idx_pbl_blueprint_tenant_status", "idxtype": "index", "idxfields": ["tenant_id", "status", "deleted"]},
{"name": "idx_pbl_blueprint_tenant_owner", "idxtype": "index", "idxfields": ["tenant_id", "owner_id"]},
{"name": "idx_pbl_blueprint_tenant_updated", "idxtype": "index", "idxfields": ["tenant_id", "deleted", "updated_at"]},
{"name": "idx_pbl_blueprint_template", "idxtype": "index", "idxfields": ["tenant_id", "template_id"]}
],
"codes": [
{"field": "status", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='pbl_bp_status'"},
{"field": "quality_status", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='pbl_quality_status'"},
{"field": "subject", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='pbl_subject'"},
{"field": "grade", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='pbl_grade'"}
]
}

View File

@ -1,234 +0,0 @@
-- pbl_blueprint DDL (MariaDB / MySQL)
-- 由 models/*.json 派生json2ddl mysql . 等价输出tenant_id 强制打头。
-- 部署:应用 build.sh 执行 json2ddl 生成;本文件为可核对的落库基线。
CREATE TABLE IF NOT EXISTS `pbl_blueprint` (
`id` VARCHAR(32) NOT NULL COMMENT '主键',
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '租户ID强制打头',
`org_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '所属机构',
`blueprint_code` VARCHAR(64) NOT NULL COMMENT '蓝图编码',
`title` VARCHAR(255) NOT NULL COMMENT '蓝图标题',
`subject_area` VARCHAR(64) DEFAULT '' COMMENT '学科领域',
`grade_level` VARCHAR(32) DEFAULT '' COMMENT '适用年级',
`duration_hours` INT DEFAULT 0 COMMENT '总课时(小时)',
`driving_question` TEXT COMMENT '驱动问题',
`summary` TEXT COMMENT '蓝图摘要',
`quality_status` VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT '5级质量状态',
`validation_score` DECIMAL(5,2) DEFAULT 0 COMMENT '校验得分',
`version_no` INT NOT NULL DEFAULT 1 COMMENT '当前版本号',
`current_version_id` VARCHAR(32) DEFAULT '' COMMENT '当前版本ID',
`template_id` VARCHAR(32) DEFAULT '' COMMENT '来源模板ID',
`forked_from_id` VARCHAR(32) DEFAULT '' COMMENT '派生自蓝图ID',
`status` VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT 'draft/published/archived/deleted',
`extra_json` LONGTEXT COMMENT '扩展属性JSON',
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_blueprint_code` (`tenant_id`,`blueprint_code`),
KEY `idx_pbl_blueprint_tenant` (`tenant_id`,`status`),
KEY `idx_pbl_blueprint_org` (`org_id`),
KEY `idx_pbl_blueprint_created` (`tenant_id`,`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='PBL蓝图聚合根';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_learning_goal` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`seq` INT NOT NULL DEFAULT 0,
`goal_code` VARCHAR(64) NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` TEXT,
`knowledge_type` VARCHAR(32) DEFAULT 'concept',
`competency_tags` TEXT,
`assessable` VARCHAR(1) DEFAULT '1',
`alignment_json` LONGTEXT,
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_goal_code` (`tenant_id`,`blueprint_id`,`goal_code`),
KEY `idx_pbl_goal_bp` (`tenant_id`,`blueprint_id`,`seq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-学习目标';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_role` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`seq` INT NOT NULL DEFAULT 0,
`role_code` VARCHAR(64) NOT NULL,
`role_name` VARCHAR(128) NOT NULL,
`description` TEXT,
`responsibilities` TEXT,
`required_skills` TEXT,
`min_members` INT DEFAULT 1,
`max_members` INT DEFAULT 1,
`is_mandatory` VARCHAR(1) DEFAULT '0',
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_role_code` (`tenant_id`,`blueprint_id`,`role_code`),
KEY `idx_pbl_role_bp` (`tenant_id`,`blueprint_id`,`seq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-PBL角色';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_mission` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`seq` INT NOT NULL DEFAULT 0,
`mission_code` VARCHAR(64) NOT NULL,
`title` VARCHAR(255) NOT NULL,
`driving_question` TEXT,
`narrative` LONGTEXT,
`success_criteria` TEXT,
`related_goal_ids` TEXT,
`duration_hours` INT DEFAULT 0,
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_mission_code` (`tenant_id`,`blueprint_id`,`mission_code`),
KEY `idx_pbl_mission_bp` (`tenant_id`,`blueprint_id`,`seq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-驱动问题/Mission';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_task` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`mission_id` VARCHAR(32) DEFAULT '',
`seq` INT NOT NULL DEFAULT 0,
`task_code` VARCHAR(64) NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` TEXT,
`task_type` VARCHAR(32) DEFAULT 'explore',
`role_id` VARCHAR(32) DEFAULT '',
`depends_on_ids` TEXT,
`estimated_minutes` INT DEFAULT 0,
`artifact_spec_ids` TEXT,
`status` VARCHAR(32) DEFAULT 'draft',
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_task_code` (`tenant_id`,`blueprint_id`,`task_code`),
KEY `idx_pbl_task_bp` (`tenant_id`,`blueprint_id`,`seq`),
KEY `idx_pbl_task_mission` (`tenant_id`,`mission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-任务';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_artifact_spec` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`task_id` VARCHAR(32) DEFAULT '',
`seq` INT NOT NULL DEFAULT 0,
`artifact_code` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`artifact_type` VARCHAR(32) DEFAULT 'document',
`format` VARCHAR(64) DEFAULT '',
`description` TEXT,
`required` VARCHAR(1) DEFAULT '1',
`max_size_mb` INT DEFAULT 0,
`schema_json` LONGTEXT,
`rubric_id` VARCHAR(32) DEFAULT '',
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_artifact_code` (`tenant_id`,`blueprint_id`,`artifact_code`),
KEY `idx_pbl_artifact_bp` (`tenant_id`,`blueprint_id`,`seq`),
KEY `idx_pbl_artifact_task` (`tenant_id`,`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-产出物规格';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_evidence_spec` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`artifact_spec_id` VARCHAR(32) DEFAULT '',
`task_id` VARCHAR(32) DEFAULT '',
`seq` INT NOT NULL DEFAULT 0,
`evidence_code` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`evidence_type` VARCHAR(32) DEFAULT 'result',
`collect_mode` VARCHAR(32) DEFAULT 'auto',
`source_hint` VARCHAR(255) DEFAULT '',
`idempotency_key_hint` VARCHAR(128) DEFAULT '',
`required` VARCHAR(1) DEFAULT '1',
`description` TEXT,
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_evidence_code` (`tenant_id`,`blueprint_id`,`evidence_code`),
KEY `idx_pbl_evidence_bp` (`tenant_id`,`blueprint_id`,`seq`),
KEY `idx_pbl_evidence_artifact` (`tenant_id`,`artifact_spec_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-证据规格';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_reflection_spec` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`seq` INT NOT NULL DEFAULT 0,
`reflection_code` VARCHAR(64) NOT NULL,
`title` VARCHAR(255) NOT NULL,
`prompt` TEXT,
`reflection_type` VARCHAR(32) DEFAULT 'self',
`trigger_point` VARCHAR(64) DEFAULT 'task_end',
`required` VARCHAR(1) DEFAULT '1',
`rubric_hint` TEXT,
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_reflection_code` (`tenant_id`,`blueprint_id`,`reflection_code`),
KEY `idx_pbl_reflection_bp` (`tenant_id`,`blueprint_id`,`seq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图子对象-反思规格';
CREATE TABLE IF NOT EXISTS `pbl_blueprint_version` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0',
`blueprint_id` VARCHAR(32) NOT NULL,
`version_no` INT NOT NULL DEFAULT 1,
`parent_version_id` VARCHAR(32) DEFAULT '',
`change_delta` LONGTEXT COMMENT '{op,path,before,after} 列表',
`snapshot_json` LONGTEXT,
`change_reason` VARCHAR(500) DEFAULT '',
`source` VARCHAR(32) DEFAULT 'manual',
`quality_status` VARCHAR(32) DEFAULT 'draft',
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_version_no` (`tenant_id`,`blueprint_id`,`version_no`),
KEY `idx_pbl_version_bp` (`tenant_id`,`blueprint_id`,`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='蓝图版本change_delta 证明对话式改模型)';
CREATE TABLE IF NOT EXISTS `pbl_template` (
`id` VARCHAR(32) NOT NULL,
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '0=平台内置全局模板',
`template_code` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` TEXT,
`category` VARCHAR(64) DEFAULT 'general',
`subject_area` VARCHAR(64) DEFAULT '',
`grade_level` VARCHAR(32) DEFAULT '',
`blueprint_snapshot` LONGTEXT,
`offline_slots` LONGTEXT COMMENT 'LLM 不可用时降级填充槽位',
`is_builtin` VARCHAR(1) DEFAULT '0',
`template_version` VARCHAR(32) DEFAULT '1.0.0',
`status` VARCHAR(32) DEFAULT 'active',
`created_by` VARCHAR(32) DEFAULT '',
`created_at` DATETIME NOT NULL,
`updated_by` VARCHAR(32) DEFAULT '',
`updated_at` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_pbl_template_code` (`tenant_id`,`template_code`),
KEY `idx_pbl_template_cat` (`tenant_id`,`category`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='PBL模板含离线兜底槽位';

View File

@ -1,44 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_artifact_spec",
"name": "蓝图产出物规格",
"title": "产出物规格",
"subtitle": "蓝图子对象-产出物规格",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "产出物规格"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "task_id", "type": "str(32)", "title": "所属任务", "default": ""},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "artifact_code", "type": "str(64)", "title": "产出物编码", "notnull": 1},
{"name": "name", "type": "str(255)", "title": "产出物名称", "notnull": 1},
{"name": "artifact_type", "type": "str(32)", "title": "产出物类型", "default": "document", "comment": "document/model/code/image/video/audio/data/other"},
{"name": "format", "type": "str(64)", "title": "文件格式", "default": ""},
{"name": "description", "type": "text", "title": "规格说明", "default": ""},
{"name": "required", "type": "str(1)", "title": "是否必需", "default": "1"},
{"name": "max_size_mb", "type": "int", "title": "大小上限(MB)", "default": 0},
{"name": "schema_json", "type": "longtext", "title": "结构约束JSON Schema", "default": ""},
{"name": "rubric_id", "type": "str(32)", "title": "评分量规ID", "default": ""},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_artifact_code", "fields": ["tenant_id", "blueprint_id", "artifact_code"], "unique": 1},
{"name": "idx_pbl_artifact_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0},
{"name": "idx_pbl_artifact_task", "fields": ["tenant_id", "task_id"], "unique": 0}
],
"codes": [
{"field": "artifact_type", "table": "appcodes_kv", "cond": "parentid='pbl_artifact_type'", "valuefield": "k", "textfield": "v"},
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"},
{"field": "task_id", "table": "pbl_blueprint_task", "cond": "", "valuefield": "id", "textfield": "title"}
]
}

View File

@ -1,45 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_evidence_spec",
"name": "蓝图证据规格",
"title": "证据规格",
"subtitle": "蓝图子对象-证据规格",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "证据规格"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "artifact_spec_id", "type": "str(32)", "title": "关联产出物规格", "default": ""},
{"name": "task_id", "type": "str(32)", "title": "关联任务", "default": ""},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "evidence_code", "type": "str(64)", "title": "证据编码", "notnull": 1},
{"name": "name", "type": "str(255)", "title": "证据名称", "notnull": 1},
{"name": "evidence_type", "type": "str(32)", "title": "证据类型", "default": "result", "comment": "process/result/behavior/log"},
{"name": "collect_mode", "type": "str(32)", "title": "采集方式", "default": "auto", "comment": "auto/manual/hybrid"},
{"name": "source_hint", "type": "str(255)", "title": "采集来源提示", "default": ""},
{"name": "idempotency_key_hint", "type": "str(128)", "title": "幂等键规则", "default": "", "comment": "供 pbl_evidence 幂等采集使用"},
{"name": "required", "type": "str(1)", "title": "是否必需", "default": "1"},
{"name": "description", "type": "text", "title": "说明", "default": ""},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_evidence_code", "fields": ["tenant_id", "blueprint_id", "evidence_code"], "unique": 1},
{"name": "idx_pbl_evidence_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0},
{"name": "idx_pbl_evidence_artifact", "fields": ["tenant_id", "artifact_spec_id"], "unique": 0}
],
"codes": [
{"field": "evidence_type", "table": "appcodes_kv", "cond": "parentid='pbl_evidence_type'", "valuefield": "k", "textfield": "v"},
{"field": "collect_mode", "table": "appcodes_kv", "cond": "parentid='pbl_collect_mode'", "valuefield": "k", "textfield": "v"},
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"},
{"field": "artifact_spec_id", "table": "pbl_blueprint_artifact_spec", "cond": "", "valuefield": "id", "textfield": "name"}
]
}

View File

@ -1,39 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_learning_goal",
"name": "蓝图学习目标",
"title": "学习目标",
"subtitle": "蓝图子对象-学习目标",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "学习目标"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "goal_code", "type": "str(64)", "title": "目标编码", "notnull": 1},
{"name": "title", "type": "str(255)", "title": "目标标题", "notnull": 1},
{"name": "description", "type": "text", "title": "目标描述", "default": ""},
{"name": "knowledge_type", "type": "str(32)", "title": "知识类型", "default": "concept", "comment": "fact/concept/procedure/metacognition"},
{"name": "competency_tags", "type": "text", "title": "素养标签JSON数组", "default": "[]"},
{"name": "assessable", "type": "str(1)", "title": "可评估", "default": "1"},
{"name": "alignment_json", "type": "longtext", "title": "对齐关系JSON", "default": ""},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_goal_code", "fields": ["tenant_id", "blueprint_id", "goal_code"], "unique": 1},
{"name": "idx_pbl_goal_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0}
],
"codes": [
{"field": "knowledge_type", "table": "appcodes_kv", "cond": "parentid='pbl_knowledge_type'", "valuefield": "k", "textfield": "v"},
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"}
]
}

View File

@ -1,38 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_mission",
"name": "蓝图Mission",
"title": "驱动问题/Mission",
"subtitle": "蓝图子对象-驱动问题",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "Mission"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "mission_code", "type": "str(64)", "title": "Mission编码", "notnull": 1},
{"name": "title", "type": "str(255)", "title": "Mission标题", "notnull": 1},
{"name": "driving_question", "type": "text", "title": "驱动问题", "default": ""},
{"name": "narrative", "type": "longtext", "title": "情境叙事", "default": ""},
{"name": "success_criteria", "type": "text", "title": "成功标准JSON数组", "default": "[]"},
{"name": "related_goal_ids", "type": "text", "title": "关联学习目标ID JSON数组", "default": "[]"},
{"name": "duration_hours", "type": "int", "title": "预计课时", "default": 0},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_mission_code", "fields": ["tenant_id", "blueprint_id", "mission_code"], "unique": 1},
{"name": "idx_pbl_mission_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0}
],
"codes": [
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"}
]
}

View File

@ -1,39 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_reflection_spec",
"name": "蓝图反思规格",
"title": "反思规格",
"subtitle": "蓝图子对象-反思规格",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "反思规格"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "reflection_code", "type": "str(64)", "title": "反思编码", "notnull": 1},
{"name": "title", "type": "str(255)", "title": "反思标题", "notnull": 1},
{"name": "prompt", "type": "text", "title": "反思提示语", "default": ""},
{"name": "reflection_type", "type": "str(32)", "title": "反思类型", "default": "self", "comment": "self/peer/team/teacher"},
{"name": "trigger_point", "type": "str(64)", "title": "触发时点", "default": "task_end", "comment": "task_end/mission_end/project_end/manual"},
{"name": "required", "type": "str(1)", "title": "是否必需", "default": "1"},
{"name": "rubric_hint", "type": "text", "title": "量规提示", "default": ""},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_reflection_code", "fields": ["tenant_id", "blueprint_id", "reflection_code"], "unique": 1},
{"name": "idx_pbl_reflection_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0}
],
"codes": [
{"field": "reflection_type", "table": "appcodes_kv", "cond": "parentid='pbl_reflect_type'", "valuefield": "k", "textfield": "v"},
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"}
]
}

View File

@ -1,39 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_role",
"name": "蓝图角色",
"title": "PBL角色",
"subtitle": "蓝图子对象-角色",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "角色"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "role_code", "type": "str(64)", "title": "角色编码", "notnull": 1},
{"name": "role_name", "type": "str(128)", "title": "角色名称", "notnull": 1},
{"name": "description", "type": "text", "title": "角色说明", "default": ""},
{"name": "responsibilities", "type": "text", "title": "职责JSON数组", "default": "[]"},
{"name": "required_skills", "type": "text", "title": "所需技能JSON数组", "default": "[]"},
{"name": "min_members", "type": "int", "title": "最少人数", "default": 1},
{"name": "max_members", "type": "int", "title": "最多人数", "default": 1},
{"name": "is_mandatory", "type": "str(1)", "title": "是否必需角色", "default": "0"},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_role_code", "fields": ["tenant_id", "blueprint_id", "role_code"], "unique": 1},
{"name": "idx_pbl_role_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0}
],
"codes": [
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"}
]
}

View File

@ -1,45 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_task",
"name": "蓝图任务",
"title": "任务",
"subtitle": "蓝图子对象-任务",
"primary": ["id"],
"defaultsort": "seq asc",
"orderby": "seq asc",
"caption": "任务"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "mission_id", "type": "str(32)", "title": "所属Mission", "default": ""},
{"name": "seq", "type": "int", "title": "序号", "notnull": 1, "default": 0},
{"name": "task_code", "type": "str(64)", "title": "任务编码", "notnull": 1},
{"name": "title", "type": "str(255)", "title": "任务标题", "notnull": 1},
{"name": "description", "type": "text", "title": "任务说明", "default": ""},
{"name": "task_type", "type": "str(32)", "title": "任务类型", "default": "explore", "comment": "explore/build/test/present/reflect"},
{"name": "role_id", "type": "str(32)", "title": "承担角色ID", "default": ""},
{"name": "depends_on_ids", "type": "text", "title": "前置任务ID JSON数组", "default": "[]"},
{"name": "estimated_minutes", "type": "int", "title": "预计耗时(分钟)", "default": 0},
{"name": "artifact_spec_ids", "type": "text", "title": "产出物规格ID JSON数组", "default": "[]"},
{"name": "status", "type": "str(32)", "title": "状态", "default": "draft"},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_task_code", "fields": ["tenant_id", "blueprint_id", "task_code"], "unique": 1},
{"name": "idx_pbl_task_bp", "fields": ["tenant_id", "blueprint_id", "seq"], "unique": 0},
{"name": "idx_pbl_task_mission", "fields": ["tenant_id", "mission_id"], "unique": 0}
],
"codes": [
{"field": "task_type", "table": "appcodes_kv", "cond": "parentid='pbl_task_type'", "valuefield": "k", "textfield": "v"},
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"},
{"field": "mission_id", "table": "pbl_blueprint_mission", "cond": "", "valuefield": "id", "textfield": "title"},
{"field": "role_id", "table": "pbl_blueprint_role", "cond": "", "valuefield": "id", "textfield": "role_name"}
]
}

View File

@ -1,36 +0,0 @@
{
"summary": [
{
"table": "pbl_blueprint_version",
"name": "蓝图版本",
"title": "蓝图版本",
"subtitle": "版本快照与变更增量",
"primary": ["id"],
"defaultsort": "version_no desc",
"orderby": "version_no desc",
"caption": "版本"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0"},
{"name": "blueprint_id", "type": "str(32)", "title": "所属蓝图", "notnull": 1},
{"name": "version_no", "type": "int", "title": "版本号", "notnull": 1, "default": 1},
{"name": "parent_version_id", "type": "str(32)", "title": "父版本ID", "default": ""},
{"name": "change_delta", "type": "longtext", "title": "变更增量JSON", "default": "", "comment": "对话式改模型的证据:{op,path,before,after} 列表"},
{"name": "snapshot_json", "type": "longtext", "title": "全量快照JSON", "default": ""},
{"name": "change_reason", "type": "str(500)", "title": "变更原因", "default": ""},
{"name": "source", "type": "str(32)", "title": "变更来源", "default": "manual", "comment": "manual/dialogue/template/fork/validation"},
{"name": "quality_status", "type": "str(32)", "title": "该版本质量状态", "default": "draft"},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1}
],
"indexes": [
{"name": "uk_pbl_version_no", "fields": ["tenant_id", "blueprint_id", "version_no"], "unique": 1},
{"name": "idx_pbl_version_bp", "fields": ["tenant_id", "blueprint_id", "created_at"], "unique": 0}
],
"codes": [
{"field": "source", "table": "appcodes_kv", "cond": "parentid='pbl_version_source'", "valuefield": "k", "textfield": "v"},
{"field": "blueprint_id", "table": "pbl_blueprint", "cond": "", "valuefield": "id", "textfield": "title"}
]
}

View File

@ -1,40 +0,0 @@
{
"summary": [
{
"table": "pbl_template",
"name": "PBL模板",
"title": "PBL模板",
"subtitle": "蓝图模板(含离线兜底槽位)",
"primary": ["id"],
"defaultsort": "created_at desc",
"orderby": "created_at desc",
"caption": "模板"
}
],
"fields": [
{"name": "id", "type": "str(32)", "title": "主键", "notnull": 1, "primary": 1, "readonly": 1},
{"name": "tenant_id", "type": "str(32)", "title": "租户ID", "notnull": 1, "default": "0", "comment": "0=平台内置全局模板,所有租户可见"},
{"name": "template_code", "type": "str(64)", "title": "模板编码", "notnull": 1},
{"name": "name", "type": "str(255)", "title": "模板名称", "notnull": 1},
{"name": "description", "type": "text", "title": "模板说明", "default": ""},
{"name": "category", "type": "str(64)", "title": "模板分类", "default": "general"},
{"name": "subject_area", "type": "str(64)", "title": "学科领域", "default": ""},
{"name": "grade_level", "type": "str(32)", "title": "适用年级", "default": ""},
{"name": "blueprint_snapshot", "type": "longtext", "title": "蓝图骨架JSON", "default": "", "comment": "实例化时展开为蓝图+子对象"},
{"name": "offline_slots", "type": "longtext", "title": "离线兜底槽位JSON", "default": "[]", "comment": "LLM 不可用时的降级填充槽位定义"},
{"name": "is_builtin", "type": "str(1)", "title": "是否内置", "default": "0"},
{"name": "template_version", "type": "str(32)", "title": "模板版本", "default": "1.0.0"},
{"name": "status", "type": "str(32)", "title": "状态", "default": "active", "comment": "active/disabled"},
{"name": "created_by", "type": "str(32)", "title": "创建人", "default": ""},
{"name": "created_at", "type": "datetime", "title": "创建时间", "notnull": 1},
{"name": "updated_by", "type": "str(32)", "title": "更新人", "default": ""},
{"name": "updated_at", "type": "datetime", "title": "更新时间"}
],
"indexes": [
{"name": "uk_pbl_template_code", "fields": ["tenant_id", "template_code"], "unique": 1},
{"name": "idx_pbl_template_cat", "fields": ["tenant_id", "category", "status"], "unique": 0}
],
"codes": [
{"field": "category", "table": "appcodes_kv", "cond": "parentid='pbl_template_cat'", "valuefield": "k", "textfield": "v"}
]
}

View File

@ -1,168 +0,0 @@
# -*- coding: utf-8 -*-
"""pbl_blueprint 表清单与字段映射(从 models/*.json 四段式定义读取,不重复硬编码字段)。
对外提供
- TABLES / TABLE_META表名清单与元信息pk / tenant_field / 抽象类型映射
- create_tables(env=None) models/*.json 建表DDL 由平台抽象类型映射生成幂等
- field_type_map(tbl)字段 -> 抽象类型交付件逐字段核对用
"""
import json
import os
from . import db as _db
MODELS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'models')
# 蓝图聚合根 + 版本 + 模板M1a 范围)
CORE_TABLES = ['pbl_blueprint', 'pbl_blueprint_version']
# 子对象 7 类M1a 落定义M1b 扩展行为)
SUBOBJECT_TABLES = [
'pbl_blueprint_mission',
'pbl_blueprint_learning_goal',
'pbl_blueprint_task',
'pbl_blueprint_role',
'pbl_blueprint_artifact_spec',
'pbl_blueprint_evidence_spec',
'pbl_blueprint_reflection_spec',
]
# 模板主表 + 明细
TEMPLATE_TABLES = ['pbl_blueprint_template', 'pbl_blueprint_template_item']
# 子对象类型 -> 表名(契约接口 subobject_save/list 的 subobject_type 取值)
SUBOBJECT_TYPE_TABLE = {
'mission': 'pbl_blueprint_mission',
'learning_goal': 'pbl_blueprint_learning_goal',
'task': 'pbl_blueprint_task',
'role': 'pbl_blueprint_role',
'artifact_spec': 'pbl_blueprint_artifact_spec',
'evidence_spec': 'pbl_blueprint_evidence_spec',
'reflection_spec': 'pbl_blueprint_reflection_spec',
}
TABLE_SUBOBJECT_TYPE = {v: k for k, v in SUBOBJECT_TYPE_TABLE.items()}
TABLES = CORE_TABLES + SUBOBJECT_TABLES + TEMPLATE_TABLES
# 抽象类型 -> PostgreSQL 物理类型(与 scripts/derive_artifacts.py 保持一致)
ABSTRACT_TO_PG = {
'str': 'varchar',
'text': 'text',
'int': 'integer',
'double': 'numeric(18,2)',
'datetime': 'timestamp',
}
# 禁止出现的物理类型/写法QC 自检项)
FORBIDDEN_TYPES = ['varchar(', 'bigint', 'boolean', 'int(11)', 'SERIAL', 'BIGSERIAL',
'nextval', 'AUTO_INCREMENT']
def _cache():
global _CACHE
if '_CACHE' not in dir():
_CACHE = {}
return _CACHE
def load_model(table):
"""读取单表四段式定义。"""
path = os.path.join(MODELS_DIR, '%s.json' % table)
if not os.path.isfile(path):
raise _db.PblError(_db.ERR_PARAM_INVALID, '表定义文件缺失: %s' % table)
with open(path, encoding='utf-8') as fp:
doc = json.load(fp)
for seg in ('summary', 'fields', 'indexes', 'codes'):
if seg not in doc:
raise _db.PblError(_db.ERR_PARAM_INVALID,
'表定义 %s 缺四段式段: %s' % (table, seg))
return doc
def all_models():
return dict((t, load_model(t)) for t in TABLES)
def field_type_map(table):
"""字段名 -> 抽象类型(如 id: str(32))。"""
return dict((k, v['type']) for k, v in load_model(table)['fields'].items())
def table_meta(table):
doc = load_model(table)
fields = doc['fields']
return {
'table': table,
'label': doc['summary'].get('label', table),
'engine': doc['summary'].get('engine', 'postgresql'),
'pk': [k for k, v in fields.items() if v.get('pk')] or ['id'],
'tenant_field': 'tenant_id' if 'tenant_id' in fields else None,
'soft_delete_field': 'is_deleted' if 'is_deleted' in fields else None,
'required': [k for k, v in fields.items() if v.get('required')],
'appcodes': doc['codes'],
'indexes': list(doc['indexes'].keys()),
'field_count': len(fields),
}
def _pg_type(spec):
ty = spec['type']
if ty.startswith('str'):
return 'varchar(%s)' % ty[ty.index('(') + 1:ty.index(')')]
if ty == 'text':
return 'text'
if ty == 'int':
return 'integer'
if ty.startswith('double'):
return 'numeric(18,2)'
if ty == 'datetime':
return 'timestamp'
raise _db.PblError(_db.ERR_PARAM_INVALID, '未知抽象类型 %s' % ty)
def create_table_ddl(table):
"""按 models/*.json 生成幂等 DDL平台抽象类型映射不写方言私有序列"""
doc = load_model(table)
fields = doc['fields']
cols = ',\n'.join(' %s %s%s' % (k, _pg_type(v),
' NOT NULL' if (v.get('required') or v.get('pk')) else '')
for k, v in fields.items())
stmts = ['CREATE TABLE IF NOT EXISTS %s (\n%s\n)' % (table, cols)]
for iname, isp in doc['indexes'].items():
if iname == 'primary':
continue
uniq = 'UNIQUE ' if isp.get('unique') else ''
stmts.append('CREATE %sINDEX IF NOT EXISTS %s_%s ON %s (%s)' %
(uniq, table, iname, table, ', '.join(isp['fields'])))
return stmts
def create_tables(tables=None, dbname=None):
"""建表(幂等)。返回 {table: 执行语句数}。"""
result = {}
for t in (tables or TABLES):
stmts = create_table_ddl(t)
for s in stmts:
_db.sql_exe(s)
result[t] = len(stmts)
return result
def register_crud(env, tables=None):
"""把 json/{tblname}.json CRUD 契约注册到 ServerEnv供平台 CRUD 工厂/前端表格消费)。"""
base = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'json')
registered = []
for t in (tables or TABLES):
path = os.path.join(base, '%s.json' % t)
if not os.path.isfile(path):
raise _db.PblError(_db.ERR_PARAM_INVALID, 'CRUD 定义缺失: %s' % path)
with open(path, encoding='utf-8') as fp:
doc = json.load(fp)
if list(doc.keys()) != [t]:
raise _db.PblError(_db.ERR_PARAM_INVALID,
'CRUD 定义根键必须等于表名 %s,实际 %s' % (t, list(doc.keys())))
if env is not None:
store = getattr(env, 'pbl_crud_defs', None)
if store is None:
store = {}
setattr(env, 'pbl_crud_defs', store)
store[t] = doc[t]
registered.append(t)
return registered