scene/skill/SKILL.md
2026-08-29 12:44:22 +08:00

74 lines
4.3 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: scene
description: 场景管理模块(W-02)——场景表 CRUD、列表查询、场景导入。提供 scene/scene_import 两张表、CRUD、分页列表接口、文件导入(api/scene_import.dspy),通过 load_scene() 挂载。枚举字段用 appcodes 字典(cond parentid=)。
---
# scene 模块
## 概述
场景管理,含场景导入。依赖 world(world_id 逻辑关联,不加物理外键)、appbase(appcodes 字典)、rbac(权限)。
## 数据模型
### 表 `scene`(models/scene.json)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | str(32) | 主键 |
| world_id | str(32) | 所属世界(→world.id,逻辑关联) |
| name | str(255) | 场景名称 |
| code | str(64) | 场景编码(唯一,idx_scene_code) |
| description | text | 描述 |
| scene_type | str(16) | 场景类型(appcodes scene_type,默认 '0') |
| status | str(16) | 状态(appcodes scene_status,默认 '0') |
| config_json | text | 场景配置 JSON |
| created_at | timestamp | 创建时间 |
| updated_at | timestamp | 更新时间 |
- 主键 `["id"]`;唯一索引 `idx_scene_code(code)`;索引 `idx_scene_world(world_id)`
- codes:world_id → world(id/name)、scene_type → appcodes_kv(parentid='scene_type')、status → appcodes_kv(parentid='scene_status')
### 表 `scene_import`(models/scene_import.json,只读)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | str(32) | 主键 |
| world_id | str(32) | 目标世界 |
| file_name | str(255) | 导入文件名 |
| total / success / fail | int | 总数 / 成功 / 失败(默认 0) |
| status | str(16) | 导入状态(appcodes import_status:0 进行中/1 成功/2 失败) |
| created_at | timestamp | 导入时间 |
- 主键 `["id"]`;索引 `idx_scene_import_world(world_id)`
## 关键接口(load_scene() 挂载到 ServerEnv)
- `list_scenes(params)` → `{list, total}`(sqlPaging 分页,支持 world_id/name/code/scene_type/status 过滤 + sort/order)
- `get_scene({id})` → `{data}` 或错误
- `create_scene(ns)` → 校验 + world 存在校验 + 自动 id/created_at/updated_at;返回 `{success, id}`
- `update_scene(ns)` → 写 updated_at、剔除 `_text` 后缀、world 校验
- `delete_scene({id})`
- `import_scenes({world_id, file_name, rows})` → `{success, total, success_count, fail}`
(**事务批量**:先全量解析+校验,再逐条插入;任一条失败整批回滚,无脏数据;success_count 表示成功条数,避免与布尔 success 冲突)
- `parse_scene_file(content, filename)` → `{rows: [...]}`(JSON 数组 / JSON Lines / CSV)
- `get_world_options()` / `get_scene_type_options()` / `get_scene_status_options()` / `get_import_status_options()` → `[{value, text}]`
### wwwroot/api/*.dspy(REST 统一前缀 /api/*,宿主挂载后为 /scene/api/*.dspy)
- `list_scenes.dspy`(分页 `{list,total}`)、`get_scene.dspy`、`create_scene.dspy`、`scene_update.dspy`、`scene_delete.dspy`
- `get_search_world_id.dspy` / `get_search_scene_type.dspy` / `get_search_status.dspy`(字典下拉)
- `scene_import.dspy`(world_id + file → parse_scene_file → import_scenes)
### 错误结构(统一)
`{code, message, field, detail}`;code:PARAM_REQUIRED / FIELD_REQUIRED / FIELD_TOO_LONG /
WORLD_NOT_FOUND / DUPLICATE_CODE / PARSE_ERROR / DB_ERROR / NOT_FOUND。非法输入 100% 拦截不落库。
## 陷阱
- 库名禁止硬编码:.py 用 `ServerEnv().get_module_dbname("scene")`,.dspy 用 `get_module_dbname("scene")`(全局);world 表在 world 模块库(`get_module_dbname("world")`)
- dspy 无 import(json/get_sor_context/debug/params_kw 均预加载全局);函数经 load_scene() 注册后为全局,直接调用
- `create_scene` / `scene_import` 必须设置 `created_at = curDateString()`,否则 sor.C 静默丢记录
- `scene_import` 记录 total/success/fail 必须为 int
- `import_scenes` 返回用 `success_count`(避免与布尔 `success` 键冲突)
- CRUD json `new_data_url` 指向自定义 `api/create_scene.dspy`;scene_import 为只读列表,无 editable
- 三处同步注册:scene/__init__.py 导出 ← scene/init.py 实现 ← load_scene() 注册
- 返回 `{list,total}` 分页用 `sor.sqlPaging`,不要硬编码 LIMIT/OFFSET
## 依赖
- world(world_id 逻辑关联 + 世界下拉)、appbase(appcodes 字典)、rbac(权限)