entity/skill/SKILL.md

64 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: entity
description: 实体管理模块(W-03)——实体表(entity)CRUD、列表查询、实体文件导入(entity_import 记录),通过 load_entity() 挂载。
---
# entity 实体管理模块
## 概述
元景项目 W-03 实体管理:管理实体(entity)数据。实体归属于场景(scene_id→scene.id,逻辑关联,不加外键)与世界(world_id→world.id)。提供实体表 CRUD、分页列表查询、CSV/JSON 文件导入(两阶段校验+批量插入+失败回滚)。
## 数据模型
| 表 | 说明 |
|----|------|
| `entity` | 实体表。`entity_code` 唯一索引;`entity_type`/`status` 引用 appcodes_kv 字典;`scene_id`/`world_id` 为逻辑外键(codes 段,无物理外键);`import_id` 标记导入批次;`org_id` 机构隔离 |
| `entity_import` | 导入批次记录(系统生成,只读)。`import_no` 唯一;`status` ∈ importing/success/fail |
| `entity_import_log` | 导入逐行明细(系统生成,只读)。`result` 1=成功 0=失败 |
编码字典(init/data.json 幂等落库 appcodes/appcodes_kv):
- `entity_type`:character/prop/vehicle/building/faction/other
- `common_status`:1=启用 / 0=停用
- `import_status`:importing/success/fail
## 关键接口(REST 统一前缀 /api/*)
| 接口 | 方法 | 说明 | 返回 |
|------|------|------|------|
| `/entity/api/entity_list.dspy` | GET/POST | 分页列表(keyword/entity_type/status/scene_id 过滤) | `{list, total, page, rows}` |
| `/entity/api/entity_create.dspy` | POST | 新增实体(校验失败 100% 拦截不落库) | `{success, data:{id}}` |
| `/entity/api/entity_update.dspy` | POST | 更新实体(校验+存在性检查) | `{success, data:{id}}` |
| `/entity/api/entity_delete.dspy` | POST | 删除实体 | `{success, data:{id}}` |
| `/entity/api/entity_get.dspy` | GET/POST | 实体详情 | `{success, data}` |
| `/entity/api/entity_import.dspy` | POST | 文件导入(file 域 / file_content) | `{success, data:{import_id,total,success,fail}}` |
| `/entity/api/entity_import_guard.dspy` | POST | 导入预校验(干跑,只校验不落库) | `{valid, errors, total}` |
| `/entity/api/entity_import_list.dspy` | GET/POST | 导入记录只读分页 | `{list, total, page, rows}` |
错误结构统一:`{code, message, field, detail}`。分页结构统一:`{list, total}`。
## 导入处理逻辑
1. **解析**:CSV(首行表头,字段 entity_code/entity_name/entity_type/scene_id/world_id/description/status/sort_no)或 JSON 数组。
2. **全量校验(第一阶段,不落库)**:编码必填/长度/文件内唯一/库内唯一;名称必填;类型/状态字典白名单;scene_id/world_id 存在性。任一行非法 → 整批拦截,只写失败批次+逐行日志,不导入任何实体。
3. **批量插入(第二阶段)**:同批实体以同一 `import_id` 标记插入;任一行异常 → 按 `import_id` 补偿 DELETE 已插入实体,保证失败回滚无脏数据。
4. 成功/失败均写 `entity_import` 批次与 `entity_import_log` 明细。
## 陷阱
- **sor.I() 只用于表结构**:插入用 `sor.C(table, ns)`,不要 `sor.I(table, data)`(I 只收 1 参)。
- **sor.U() 只收 2 参**:`sor.U('entity', {**upd, 'id': id})`,id 必须在 data 内;仅主键字段时先校验非空字段。
- **dspy 中禁 import**:全部函数经 `load_entity()` 注册为全局(`create_entity/update_entity/delete_entity/get_entity/list_entities/import_entities/entity_import_guard/reject_import_write`),dspy 直接调用;`__init__.py` 必须导出 init.py 的 async 函数,否则 NameError。
- **取库名不硬编码**:.py 用 `get_sor_context(ServerEnv(), 'entity')`(内部解析 `get_module_dbname('entity')`);.dspy 用 `get_sor_context(request._run_ns, 'entity')`。禁止写 `DBNAME='...'`。
- **请求上下文**:.py 内取用户/机构用 `request._run_ns`(get_user/get_userorgid),不要用 `ServerEnv()`(进程级单例)。
- **`_text` 后缀字段**:表格提交会带 `xxx_text`,`_clean_ns` 会剔除后再写库。
- **curDateString()**:sqlor 不自动写时间戳,插入必须显式 `created_at`,否则记录静默丢失。
- **删除校验**:entity 可能被 world_snapshot 等引用,删除前可扩展引用检查(当前实现仅校验存在性)。
## 依赖
- 基础:sqlor、ahserver、appPublic
- 数据依赖(逻辑关联,不物理外键):`scene`(scene.id)、`world`(world.id)——codes 段引用,表缺失时仅下拉不渲染,不影响 CRUD
- 字典:appbase 的 appcodes / appcodes_kv
- 被 `world_snapshot`(W-03 快照)聚合读取