74 lines
4.3 KiB
Markdown
74 lines
4.3 KiB
Markdown
---
|
||
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(权限)
|