From a9a938a2604e6baad8f2f7dd32bd1d1390c67be9 Mon Sep 17 00:00:00 2001 From: "agent.develop" Date: Tue, 13 Oct 2026 14:48:36 +0800 Subject: [PATCH] =?UTF-8?q?approve:=20=E5=A4=8D=E6=B5=8B=E5=B7=B2=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20Bug=EF=BC=88pbls-=E5=88=9D=E5=A7=8B=E8=BF=AD?= =?UTF-8?q?=E4=BB=A3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pbl_assessment/seed.py | 183 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 pbl_assessment/seed.py diff --git a/pbl_assessment/seed.py b/pbl_assessment/seed.py new file mode 100644 index 0000000..8f0527e --- /dev/null +++ b/pbl_assessment/seed.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +"""pbl_assessment 种子数据 —— Rubric 默认量规 rubric_default_5level(幂等注入)。 + +对应 env/test.json seed.items[3]:Rubric 默认量规 rubric_default_5level(5 级准则)。 +种子数据使用 __system__ 租户,由 build.sh 第 12 步种子段调用。 + +幂等策略:按 rubric.code 存在即跳过(不更新、不覆盖),二次执行零差异。 +""" + +import json +import time +import hashlib + +MODULE = 'pbl_assessment' +TBL_RUBRIC = 'pbl_rubric' +TBL_RUBRIC_CRITERION = 'pbl_rubric_criterion' +SYSTEM_TENANT = '__system__' + +# ---- 默认量规定义(5 级准则,权重合计 100%)---- +DEFAULT_RUBRIC = { + "tenant_id": SYSTEM_TENANT, + "id": "rubric_default_5level", + "code": "RUBRIC_DEFAULT_5LEVEL", + "title": "PBL 通用量规(5 级)", + "blueprint_id": "", + "criteria_json": json.dumps([ + { + "code": "C01_PROBLEM_DEFINITION", + "name": "问题定义与理解", + "learning_goal_id": "LG_PROBLEM", + "weight": 20.0, + "max_points": 5, + "descriptors": { + "5": "独立识别复杂问题,提出清晰且可验证的问题陈述", + "4": "识别主要问题,提出可验证的问题陈述", + "3": "在引导下识别问题,问题陈述基本清晰", + "2": "问题识别不完整,问题陈述模糊", + "1": "无法识别问题或问题陈述缺失", + }, + }, + { + "code": "C02_RESEARCH_INQUIRY", + "name": "探究与研究", + "learning_goal_id": "LG_RESEARCH", + "weight": 20.0, + "max_points": 5, + "descriptors": { + "5": "多源系统性探究,数据收集方法科学,分析深入", + "4": "使用多种可靠来源,分析有逻辑支撑", + "3": "使用2-3个来源,分析基本合理", + "2": "来源单一或不可靠,分析缺乏深度", + "1": "未进行有效探究或数据来源不明", + }, + }, + { + "code": "C03_SOLUTION_DESIGN", + "name": "方案设计与创新", + "learning_goal_id": "LG_DESIGN", + "weight": 25.0, + "max_points": 5, + "descriptors": { + "5": "方案具有原创性、可行性高,考虑了约束与取舍", + "4": "方案可行且有一定创新元素", + "3": "方案可用但创新性不足", + "2": "方案存在明显缺陷或不完整", + "1": "方案不可行或与问题无关", + }, + }, + { + "code": "C04_IMPLEMENTATION", + "name": "实施与执行", + "learning_goal_id": "LG_IMPLEMENT", + "weight": 20.0, + "max_points": 5, + "descriptors": { + "5": "按计划高质量完成全部交付,超出预期", + "4": "按计划完成交付,质量良好", + "3": "基本完成任务,质量可接受", + "2": "部分任务完成,存在质量缺陷", + "1": "未完成核心任务或质量不合格", + }, + }, + { + "code": "C05_REFLECTION_COMMUNICATION", + "name": "反思与沟通", + "learning_goal_id": "LG_REFLECT", + "weight": 15.0, + "max_points": 5, + "descriptors": { + "5": "深刻反思学习过程,沟通清晰有说服力,回应自如", + "4": "有反思内容,表达清晰", + "3": "有基本反思与表达", + "2": "反思表面化或表达不清", + "1": "缺少反思或沟通无效", + }, + }, + ], ensure_ascii=False), + "total_weight": 100.00, + "version_no": 1, + "status": "active", + "approval_id": "", +} + +# 量规准则表(与 pbl_rubric 一对多,每条准则一行) +SEED_CRITERIA = [] +for c in json.loads(DEFAULT_RUBRIC['criteria_json']): + SEED_CRITERIA.append({ + "tenant_id": SYSTEM_TENANT, + "id": "criterion_%s" % c['code'].lower(), + "rubric_code": "RUBRIC_DEFAULT_5LEVEL", + "code": c['code'], + "name": c['name'], + "learning_goal_id": c.get('learning_goal_id', ''), + "weight": c['weight'], + "max_points": c['max_points'], + "descriptors_json": json.dumps(c.get('descriptors', {}), ensure_ascii=False), + "sort_no": list(c['code'] for c in json.loads(DEFAULT_RUBRIC['criteria_json'])).index(c['code']) * 10 + 10, + }) + + +async def seed_rubrics(dbname=None, tenant_id=None): + """幂等写入默认量规种子。 + + :param dbname: 可选,数据库名(缺省自动解析) + :param tenant_id: 可选,租户 ID(缺省使用 __system__) + :return: dict {ok, rubrics_inserted, criteria_inserted, errors} + """ + from pbl_common.api import sql_exe, sql_rows + import time as _time + + tid = tenant_id or SYSTEM_TENANT + now = str(int(_time.time() * 1000)) + result = {"ok": True, "rubrics_inserted": 0, "criteria_inserted": 0, "errors": []} + + # ---- 量规表 ---- + exist = await sql_rows( + 'SELECT id FROM `%s` WHERE `tenant_id` = ${t}$ AND `code` = ${c}$ LIMIT 1' + % TBL_RUBRIC, {'t': tid, 'c': DEFAULT_RUBRIC['code']}) + if not exist: + try: + row = dict(DEFAULT_RUBRIC) + row['tenant_id'] = tid + row.setdefault('create_time', now) + row.setdefault('update_time', now) + cols = ','.join('`%s`' % k for k in row) + vals = ','.join('${%s}$' % k for k in row) + await sql_exe('INSERT INTO `%s` (%s) VALUES (%s)' % (TBL_RUBRIC, cols, vals), row) + result['rubrics_inserted'] = 1 + except Exception as exc: + err = '默认量规写入失败: %s' % exc + result['errors'].append(err) + print('[pbl_assessment.seed][WARN] %s' % err) + + # ---- 量规准则表 ---- + for crit in SEED_CRITERIA: + try: + exist_c = await sql_rows( + 'SELECT id FROM `%s` WHERE `tenant_id` = ${t}$ AND `code` = ${c}$ LIMIT 1' + % TBL_RUBRIC_CRITERION, {'t': tid, 'c': crit['code']}) + if exist_c: + continue + + row = dict(crit) + row['tenant_id'] = tid + row.setdefault('create_time', now) + row.setdefault('update_time', now) + cols = ','.join('`%s`' % k for k in row) + vals = ','.join('${%s}$' % k for k in row) + await sql_exe('INSERT INTO `%s` (%s) VALUES (%s)' % (TBL_RUBRIC_CRITERION, cols, vals), row) + result['criteria_inserted'] += 1 + except Exception as exc: + err = '准则 %s 写入失败: %s' % (crit.get('code'), exc) + result['errors'].append(err) + print('[pbl_assessment.seed][WARN] %s' % err) + + result['ok'] = len(result['errors']) == 0 + return result + + +def seed_all_sync(dbname=None, tenant_id=None): + """同步包装(供 build.sh heredoc 裸调)。""" + import asyncio + return asyncio.run(seed_rubrics(dbname=dbname, tenant_id=tenant_id)) \ No newline at end of file