first commit
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
---
|
||||
applyTo: '**'
|
||||
---
|
||||
在任何情况系下, 禁止修改schemas文件夹的内容!
|
||||
|
||||
你的目标是基于它,生成一个类型安全的推送系统测试脚本,而不是修改类型系统!
|
||||
|
||||
也不要改filtered_datasource。这个是测试用的数据源。
|
||||
|
||||
也不要因为报错就绕过schema校验。如果schema校验报错,那就让它报,我自然会去修。
|
||||
|
||||
遇到报错或者走不通的路,不要轻易偏离文档,做降级处理,而是要多报错,直到我说可以降级处理再说。
|
||||
|
||||
不要在项目根目录乱写测试。测试写到tests里。
|
||||
|
||||
不要乱加fallback,所有fallback类的逻辑都需要让我确认过了才行。
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
# Local data
|
||||
*.sqlite3
|
||||
*.db
|
||||
*.log
|
||||
*.pot
|
||||
*.mo
|
||||
*.pkl
|
||||
# *.jsonl
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# User-specific
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Ignore data and filtered data
|
||||
# filtered_datasource/
|
||||
remote_datasource/
|
||||
working_local_datasource/
|
||||
tmp_remote_datasource/
|
||||
tmp_jsonl_ds/
|
||||
|
||||
# Ignore test outputs
|
||||
*.out
|
||||
|
||||
# ignore examples
|
||||
v2/
|
||||
temp_test_output/
|
||||
zerocoach/
|
||||
Zerocoach/
|
||||
.env
|
||||
# User-created run profiles
|
||||
run_profiles/*.json
|
||||
run_profiles/*.yaml
|
||||
run_profiles/*.yml
|
||||
# Sync System Runtime Data
|
||||
_runtime/
|
||||
test_results/
|
||||
@@ -0,0 +1,90 @@
|
||||
# test_push_system
|
||||
|
||||
## 1. 项目简介
|
||||
|
||||
本项目用于实现异构系统之间的数据推送:将项目侧管理平台的十余种业务数据,稳定推送到集团侧管理平台。
|
||||
|
||||
核心复杂点包括:
|
||||
- 数据接口复杂且会随业务变化。
|
||||
- 业务之间依赖关系复杂(跨业务、跨阶段)。
|
||||
- 同业务数据的双侧对应关系判定复杂(绑定/自动绑定)。
|
||||
- 同步流程各步骤可能出错,系统需要自动处理,必要时允许人工介入。
|
||||
- 字段多且杂,且可能由不同更新接口共同影响同一业务信息。
|
||||
|
||||
## 2. 项目架构
|
||||
|
||||
项目采用:`schema` 严格约束 + 状态机 + 节点模型 + 分层架构 + 注册式 `domain` + 数据源与同步系统解耦。
|
||||
|
||||
架构详见:
|
||||
- `docs/architecture.md`
|
||||
- `docs/node_state_definition.md`
|
||||
- `docs/state_machine.md`
|
||||
|
||||
## 3. 同步过程简述
|
||||
|
||||
整体流程可理解为:
|
||||
1. Pipeline 读取配置并初始化数据源、策略、状态机运行时。
|
||||
2. 加载本地与远端节点,进入绑定/依赖检查/自动绑定阶段。
|
||||
3. 按状态机判定进入 create / update / delete 准备与执行阶段。
|
||||
4. 执行结果回写节点状态并持久化,失败进入可观测、可重试或可人工处理状态。
|
||||
|
||||
状态机的作用:
|
||||
- 把复杂业务规则收敛为可验证、可追踪的事件迁移。
|
||||
- 保证不变量(invariant)在运行期可检查。
|
||||
- 统一错误处理路径,避免“隐式分支”造成不一致。
|
||||
|
||||
示意图:
|
||||
- `docs/state_machine.svg`
|
||||
|
||||
流程与时序详见:
|
||||
- `docs/state_machine.md`
|
||||
- `docs/sync_flow.md`
|
||||
|
||||
## 4. 后续开发(扩展新数据源)
|
||||
|
||||
建议路径:
|
||||
1. 在 `sync_state_machine/domain/` 增加业务 `schema / node / strategy` 并注册到 DomainRegistry。
|
||||
2. 在 `sync_state_machine/datasource/` 实现新数据源 handler(load/create/update/delete/poll)。
|
||||
3. 参考 `run_profiles/preset/` 模板,在 `run_profiles/` 自建对应运行配置,先走 JSONL/Mock 集成测试,再接真实接口。
|
||||
4. 根据业务特性补充状态机上下文字段与测试用例,确保状态迁移可验证。
|
||||
|
||||
可参考:
|
||||
- `sync_state_machine/datasource/README.md`
|
||||
- `docs/runtime_config_guide.md`
|
||||
- `tests/README.md`
|
||||
|
||||
## 5. 使用方法
|
||||
|
||||
### JSONL 同步
|
||||
- 基线配置(优先):`python run.py --config_path=run_profiles/preset/jsonl_to_jsonl.default.yaml`
|
||||
- 使用自定义配置:先从 `run_profiles/preset/jsonl_to_jsonl.default.yaml` 复制到 `run_profiles/jsonl_to_jsonl.local.yaml`,按需修改后运行:`python run.py --config_path=run_profiles/jsonl_to_jsonl.local.yaml`
|
||||
|
||||
### API 同步
|
||||
- 基线配置:`python run.py --config_path=run_profiles/preset/jsonl_to_api.default.yaml`
|
||||
- 使用自定义配置:先从 `run_profiles/preset/jsonl_to_api.default.yaml` 复制到 `run_profiles/jsonl_to_api.local.yaml`,按需修改后运行:`python run.py --config_path=run_profiles/jsonl_to_api.local.yaml`
|
||||
|
||||
### 配置与校验
|
||||
- 模板配置:`run_profiles/preset/*.default.yaml`
|
||||
- 建议先跑 default,再在 `run_profiles/*.local.yaml` 做覆盖(该目录 YAML 已默认忽略)
|
||||
- 状态机配置校验:`python tools/validate_config.py --config sync_state_machine/config/node_state_machine.yaml`
|
||||
- 状态机图生成:`python tools/render_graph.py --format mermaid --out docs/state_machine.mmd`
|
||||
|
||||
### 测试
|
||||
- 全量:`pytest tests -q`
|
||||
- 说明:`tests/README.md`
|
||||
|
||||
### 其他工具
|
||||
- UI 调试:`python -m ui.main --host 127.0.0.1 --port 8765`
|
||||
- 运维与排障:`docs/operations.md`
|
||||
|
||||
## 文档导航
|
||||
|
||||
- 总体架构:`docs/architecture.md`
|
||||
- 状态定义:`docs/node_state_definition.md`
|
||||
- 状态机规则:`docs/state_machine.md`
|
||||
- 同步流程:`docs/sync_flow.md`
|
||||
- 运行配置:`docs/runtime_config_guide.md`
|
||||
- Collection 查询与升级:`docs/collection_query_and_upgrade_plan.md`
|
||||
- 运维迭代:`docs/operations.md`
|
||||
|
||||
历史资料已归档到 `docs/archive/`。
|
||||
@@ -0,0 +1,66 @@
|
||||
# 同步系统整体框架
|
||||
|
||||
## 1. 分层职责(pipeline + strategy + datasource + domain)
|
||||
|
||||
### pipeline(编排层)
|
||||
- 入口:`pipeline/full_sync_pipeline.py`
|
||||
- 负责组装并驱动整条流程:加载持久化、执行 bind/create/update、调用 datasource 同步、持久化结果。
|
||||
- reset 语义:
|
||||
- 加载阶段仅恢复持久化状态(不做状态重置);
|
||||
- 加载后通过 `BaseSyncStrategy.run_reset()` 触发 `E01`:
|
||||
- `create_zombie=true` -> `S15`(随后删除);
|
||||
- `create_zombie=false` -> `S00`(归并为 `UNCHECKED/NONE/PENDING`,并清空 `error`)。
|
||||
- 若持久化核心枚举非法(`action/status/binding_status`),节点进入加载异常隔离态 `S17`:
|
||||
- 保留错误信息供人工介入;
|
||||
- 不参与 `E01` 与后续 bind/create/update/sync 自动流程。
|
||||
|
||||
### pipeline 运行语境(人工介入 + 可变配置)
|
||||
- 运行前可按批次调整策略配置(例如“首轮先拉取、后续只推送”),属于 pipeline 的一次性运行参数。
|
||||
- 人工介入分两段:
|
||||
- **运行前**:可手工修复数据、手工绑定、调整策略参数;
|
||||
- **运行后**:根据节点 `status/error/sync_log` 处理异常(为未来 GUI 介入提供依据)。
|
||||
- 若上轮异常未人工处理,本轮在 `E01` 先做归并/清理:
|
||||
- CREATE 僵尸节点自动删除并解除绑定残留;
|
||||
- 非僵尸节点统一进入 `S00`,再进入本轮 bind/create/update 判定。
|
||||
|
||||
### strategy(决策组织层)
|
||||
- 外部入口:`sync_system/strategy.py`
|
||||
- 具体实现下沉:`sync_system/strategy_ops/`
|
||||
- `bind_ops.py`: `run_bind()` + `phase_core_state()/phase_dependency_check()/phase_auto_binding()`
|
||||
- `create_ops.py`: `run_create()`
|
||||
- `update_ops.py`: `run_update()`
|
||||
- `delete_ops.py`: `run_delete()`
|
||||
- `reset_ops.py`: `get_phase1_reset_defaults()/run_phase2_cleanup()`
|
||||
- strategy 负责收集上下文并调用状态机事件函数,不直接硬编码状态值。
|
||||
|
||||
### datasource(执行与回写层)
|
||||
- 入口:`datasource/datasource.py`
|
||||
- 执行 handler(create/update/delete),并结合 `E40` 将执行结果落地到节点状态。
|
||||
|
||||
### domain(业务适配层)
|
||||
- 目录:`domain/*`
|
||||
- 负责业务字段映射、handler 细节与 schema 约束,不承担状态迁移判定。
|
||||
|
||||
## 2. 运行时契约(Runtime Contract)
|
||||
|
||||
### 真源
|
||||
- 状态机配置真源:`config/node_state_machine.yaml`
|
||||
- 事件执行入口:`engine/events.py`
|
||||
- 状态落地入口:`engine/state_apply.py`
|
||||
|
||||
### 执行规则
|
||||
1. 业务层构造 `context`。
|
||||
2. 调用 `StateMachineRuntime.dispatch(current_state, event_id, context)`。
|
||||
3. 依据 `Decision.to_state` 从 YAML `states[Sxx]` 落地 `binding_status/action/status`。
|
||||
4. `Decision.emit` 只用于状态外副作用(spawn、绑定、调用 handler 等)。
|
||||
5. 每次事件落地后,`events._apply_decision` 调用 `runtime.check_invariants()`;违反直接抛错。
|
||||
|
||||
## 3. 边界与约束
|
||||
- `strategy/datasource` 不应绕过状态机直接写最终状态。
|
||||
- `PRECONDITION_FAILED` 必须满足 `action=UPDATE`(YAML invariant 强约束)。
|
||||
- 依赖语义由 strategy 计算(如 `dep_satisfied/dep_errors`),状态机只消费语义结果并迁移。
|
||||
|
||||
## 4. 相关文档
|
||||
- 框架与流程:`docs/sync_flow.md`
|
||||
- 节点状态定义:`docs/node_state_definition.md`
|
||||
- 状态机形式化说明:`docs/state_machine.md`
|
||||
@@ -0,0 +1,11 @@
|
||||
# 文档归档说明
|
||||
|
||||
本目录存放历史文档,不作为当前实现规范。
|
||||
|
||||
- `from_root_docs/`:从旧位置迁移的历史文档快照。
|
||||
- `conflict_log.md` / `goals.md` / `migration_map.md`:重构过程文档。
|
||||
|
||||
遇到冲突时,请以 `docs/` 根目录下现行文档和代码真源为准:
|
||||
- `config/node_state_machine.yaml`
|
||||
- `engine/events.py`
|
||||
- `sync_system/strategy_ops/*`
|
||||
@@ -0,0 +1,10 @@
|
||||
# 文档/实现冲突记录
|
||||
|
||||
## 已确认冲突
|
||||
- 旧文档中存在 E11x 编号残留,与当前 YAML(E08/E09/E10/E12..E20) 不一致。
|
||||
- `PRECONDITION_FAILED` 在旧实现中可能出现 `action=NONE`,重构目标改为强制 `action=UPDATE`。
|
||||
|
||||
## 处理原则
|
||||
1. 以 `config/node_state_machine.yaml` 为唯一真源。
|
||||
2. 文档必须由配置和测试结果反向校验。
|
||||
3. 冲突先记录,再通过测试保护修复。
|
||||
@@ -0,0 +1,706 @@
|
||||
# API DataSource 架构设计
|
||||
|
||||
## 架构总览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Pipeline │
|
||||
│ (同步流程编排) │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ApiDataSource │
|
||||
│ (数据源协调层) │
|
||||
│ │
|
||||
│ - 持有 ApiClient 实例 │
|
||||
│ - 注册和管理 Handler │
|
||||
│ - 实现 load_all / execute_batch │
|
||||
│ - 注入 api_client 到 Handler │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ Handler │ │ Handler │ │ Handler │
|
||||
│ Project │ │ Contract │ │ Material │
|
||||
│ │ │ │ │ │
|
||||
│ 业务逻辑层 │ │ 业务逻辑层 │ │ 业务逻辑层 │
|
||||
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
||||
│ │ │
|
||||
└───────────────────┼───────────────────┘
|
||||
│ 使用 self.api_client
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ ApiClient │
|
||||
│ (HTTP 通信层) │
|
||||
│ │
|
||||
│ - 签名生成 │
|
||||
│ - HTTP 请求 │
|
||||
│ - Push Log │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
**调用流程**:
|
||||
1. Pipeline 创建 ApiDataSource,传入 base_url, uid, secret
|
||||
2. ApiDataSource 内部创建 ApiClient 实例
|
||||
3. ApiDataSource 注册各业务 Handler,并注入 api_client
|
||||
4. Handler 使用 `self.api_client.get/post/put()` 发送请求
|
||||
5. ApiClient 自动处理签名、push_log 查询、错误处理
|
||||
|
||||
**优势**:
|
||||
- ✅ **职责清晰**:ApiClient(通信)、DataSource(协调)、Handler(业务)
|
||||
- ✅ **避免循环依赖**:Handler → ApiClient(单向依赖)
|
||||
- ✅ **易于测试**:ApiClient 可 mock,Handler 独立测试
|
||||
- ✅ **易于扩展**:新业务只需实现 Handler
|
||||
|
||||
## 1. 问题分析:旧方案的复杂性
|
||||
|
||||
旧方案 `sync_system/datasource/api` 存在的问题:
|
||||
|
||||
1. **过度抽象**:引入了 `ApiDataSource` → `Repository` → `ResponseHandle` → `Cache` 多层封装,每个业务需要独立 Repository 类,Protocol 定义繁琐
|
||||
2. **状态管理混乱**:缓存策略不清晰,ResponseHandle 封装异步结果但使用困难,缺少统一的 push_log 查询机制
|
||||
3. **依赖关系困难**:Repository 之间互相传递引用,难以从 collection 获取已有数据
|
||||
4. **API 路由分散**:每个 Repository 手动实现多个 update 方法,缺少自动路由机制
|
||||
|
||||
## 2. 新方案设计原则
|
||||
|
||||
- **简单直接**:Handler 直接调用 HTTP API,不过度封装
|
||||
- **状态透明**:DataSource 统一管理 session、签名、push_log 查询
|
||||
- **依赖清晰**:通过 collection 获取依赖数据,使用 context 存储额外信息
|
||||
- **智能路由**:根据数据字段自动选择 API endpoint
|
||||
|
||||
## 3. 核心组件职责
|
||||
|
||||
### 3.1 ApiClient - HTTP 通信层
|
||||
|
||||
**职责**:
|
||||
- 封装所有 HTTP 通信逻辑
|
||||
- 管理 httpx.AsyncClient,维护连接池和 session
|
||||
- 生成请求签名(timestamp, nonce, sign)
|
||||
- 统一请求入口,自动注入 uid
|
||||
- 批量 Push Log 查询
|
||||
|
||||
**核心方法**:
|
||||
```python
|
||||
class ApiClient:
|
||||
def __init__(self, base_url: str, uid: str, secret: str):
|
||||
self._client = httpx.AsyncClient()
|
||||
self._base_url = base_url
|
||||
self._uid = uid
|
||||
self._secret = secret
|
||||
|
||||
async def request(self, method: str, url: str, **kwargs) -> httpx.Response
|
||||
"""统一请求入口,自动签名"""
|
||||
|
||||
async def get(self, url: str, params: dict = None) -> httpx.Response
|
||||
"""GET 请求"""
|
||||
|
||||
async def post(self, url: str, data: dict) -> httpx.Response
|
||||
"""POST 请求,data 中已包含 push_id/biz_id(由 Handler 生成)"""
|
||||
|
||||
async def put(self, url: str, data: dict) -> httpx.Response
|
||||
"""PUT 请求,data 中已包含 push_id/biz_id"""
|
||||
|
||||
async def delete(self, url: str, data: dict) -> httpx.Response
|
||||
"""DELETE 请求,data 中已包含 push_id/biz_id"""
|
||||
|
||||
async def get_push_logs(self, push_ids: List[str]) -> Dict[str, dict]
|
||||
"""批量查询 push_log 状态,返回 {push_id: push_log_data}
|
||||
注意:单个查询也传单元素列表
|
||||
当前实现:用 for 循环模拟,后续等后端实现批量接口
|
||||
"""
|
||||
|
||||
def _generate_signature(self, params: dict) -> dict
|
||||
"""生成签名参数(timestamp, nonce, sign)"""
|
||||
```
|
||||
|
||||
### 3.2 ApiDataSource - 数据源协调层
|
||||
|
||||
**职责**:
|
||||
- 持有 ApiClient 实例,提供给 Handler 使用
|
||||
- 实现 DataSource 接口(load_all, sync_all)
|
||||
- 协调多个 Handler 的执行顺序(通过 sync_all)
|
||||
- Handler 内部负责:生成 push_id/biz_id、调用 poll 轮询、提取 created_id
|
||||
- 统一异常处理和日志记录
|
||||
|
||||
**核心属性和方法**:
|
||||
```python
|
||||
class ApiDataSource(DataSource):
|
||||
def __init__(self, base_url: str, uid: str, secret: str):
|
||||
self.client = ApiClient(base_url, uid, secret)
|
||||
self._handlers: Dict[str, BaseApiHandler] = {}
|
||||
|
||||
def register_handler(self, node_type: str, handler: BaseApiHandler):
|
||||
"""注册业务 Handler"""
|
||||
handler.api_client = self.client # 注入 client
|
||||
self._handlers[node_type] = handler
|
||||
|
||||
async def load_all(self, collection: DataCollection, order: List[str]) -> None:
|
||||
"""调用基类的 load_all,按顺序加载数据"""
|
||||
|
||||
async def sync_all(self, collection: DataCollection, order: List[str]) -> None:
|
||||
"""调用基类的 sync_all,按顺序执行同步"""
|
||||
```
|
||||
|
||||
### 3.3 BaseApiHandler - 业务逻辑基类
|
||||
|
||||
**职责**:
|
||||
- 实现 Handler 接口(load, create, update, delete, poll)
|
||||
- 使用 self.api_client 发送 HTTP 请求
|
||||
- 生成 push_id 和 biz_id(业务标识)
|
||||
- 从 collection 获取依赖节点数据
|
||||
- 管理节点的 context(存储 project_id, contract_id 等)
|
||||
- 实现 poll 方法,调用 api_client.get_push_logs 批量查询
|
||||
- 提取 created_id(因为不同业务的 id 字段名和位置可能不同)
|
||||
- 返回 TaskResult(SUCCESS/FAILED/IN_PROGRESS)
|
||||
|
||||
**核心方法**:
|
||||
```python
|
||||
class BaseApiHandler(NodeHandler):
|
||||
def __init__(self):
|
||||
self.api_client: ApiClient = None # 由 DataSource 注入
|
||||
self.collection: DataCollection = None # 由 DataSource 注入
|
||||
|
||||
async def load(self, collection: DataCollection) -> List[dict]
|
||||
async def create(self, node: SyncNode) -> TaskResult
|
||||
async def update(self, node: SyncNode) -> TaskResult
|
||||
async def delete(self, node: SyncNode) -> TaskResult
|
||||
async def poll(self, node: SyncNode, task_id: str) -> TaskResult
|
||||
|
||||
def extract_created_id(self, push_log: dict) -> str
|
||||
"""从 push_log 提取 created_id,子类可重写"""
|
||||
|
||||
# 重试逻辑(可选,子类可重写)
|
||||
async def _execute_with_retry(self, operation, max_retries: int = 3) -> Any
|
||||
"""通用重试逻辑,子类可自定义重试策略"""
|
||||
```
|
||||
|
||||
**重试策略说明**:
|
||||
- **重试在 Handler 内部**:create/update/delete 内部可调用 _execute_with_retry
|
||||
- **返回给 DataSource**:最终只返回 SUCCESS/FAILED/IN_PROGRESS
|
||||
- **灵活控制**:不同业务可重写 _execute_with_retry 实现自定义策略
|
||||
- **默认策略**:网络错误/5xx 重试 3 次,4xx 不重试
|
||||
|
||||
**未实现 API 的处理**:
|
||||
- 部分业务可能没有实现 create 或 delete API
|
||||
- 此时 Handler 应在对应方法中直接返回 FAILED 状态,并在 error 中说明原因
|
||||
- 示例:`return TaskResult(status=TaskStatus.FAILED, error="Create API not implemented for this business")`
|
||||
|
||||
### 3.4 具体业务 Handler
|
||||
|
||||
**职责**:
|
||||
- 实现具体业务的 load 逻辑(调用 self.api_client.get())
|
||||
- 创建节点时设置 context
|
||||
- 重写 API endpoint 选择逻辑(可选)
|
||||
- 定制 created_id 提取逻辑(可选)
|
||||
|
||||
每个业务 Handler 位于 `sync_system_new/domain/{业务}/api_handler.py`
|
||||
|
||||
## 4. HTTP 请求状态管理
|
||||
|
||||
### 4.0 状态系统概述
|
||||
|
||||
**通用状态枚举**(适用于所有 DataSource):
|
||||
|
||||
```python
|
||||
class TaskStatus(Enum):
|
||||
"""Handler 返回的任务执行状态"""
|
||||
SUCCESS = "success" # 同步完成,立即成功
|
||||
FAILED = "failed" # 同步失败
|
||||
IN_PROGRESS = "in_progress" # 异步任务进行中
|
||||
|
||||
class SyncStatus(Enum):
|
||||
"""SyncNode 的同步执行状态"""
|
||||
PENDING = "PENDING"
|
||||
IN_PROGRESS = "IN_PROGRESS"
|
||||
SUCCESS = "SUCCESS"
|
||||
FAILED = "FAILED"
|
||||
SKIPPED = "SKIPPED"
|
||||
PRECONDITION_FAILED = "PRECONDITION_FAILED"
|
||||
```
|
||||
|
||||
**状态映射规则**:
|
||||
- TaskStatus 是 Handler 执行操作后的返回值
|
||||
- SyncStatus 是 SyncNode 的最终状态,由 DataSource 根据 TaskStatus 更新
|
||||
- 普通 DataSource(FileDataSource)和 API DataSource 使用相同的状态枚举
|
||||
- 区别在于:**API DataSource 的网络操作如何转化为 TaskStatus**
|
||||
|
||||
**重要说明:Load 阶段 vs 执行阶段的状态**:
|
||||
- **Load 阶段**(Handler.load()):从 API 拉取数据创建 SyncNode
|
||||
- 此时节点状态为 `PENDING`(等待后续 bind/create/update)
|
||||
- GET 请求失败不影响节点创建,只是该节点不存在于 collection
|
||||
- **执行阶段**(Handler.create/update/delete):执行同步操作
|
||||
- DataSource 在调用前设置 `node.status = IN_PROGRESS`
|
||||
- Handler 返回 TaskResult,DataSource 据此更新 node.status
|
||||
- POST/PUT/DELETE 成功后才设置为 SUCCESS
|
||||
|
||||
**核心映射逻辑**(在 DataSource 中):
|
||||
```python
|
||||
# 执行前:DataSource 设置状态
|
||||
node.status = SyncStatus.IN_PROGRESS
|
||||
|
||||
# 调用 Handler(Handler 内部可能重试多次)
|
||||
result = await handler.create(node)
|
||||
|
||||
# 执行后:DataSource 根据最终结果更新状态
|
||||
if result.status == TaskStatus.SUCCESS:
|
||||
node.status = SyncStatus.SUCCESS
|
||||
node.data_id = result.data_id
|
||||
elif result.status == TaskStatus.FAILED:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = result.error
|
||||
elif result.status == TaskStatus.IN_PROGRESS:
|
||||
# 记录 task_id 等待轮询
|
||||
async_tasks[node.node_id] = result.task_id
|
||||
```
|
||||
|
||||
**重要**:Handler 负责重试,最终只返回确定的结果(SUCCESS/FAILED/IN_PROGRESS)
|
||||
|
||||
### 4.1 请求类型与状态流转
|
||||
|
||||
**API DataSource 的特殊性**:
|
||||
- **Load 阶段**:GET 请求拉取数据,创建 PENDING 节点(失败则不创建节点)
|
||||
- **执行阶段**:POST/PUT/DELETE 先设置 IN_PROGRESS,通过 poll() 轮询变为 SUCCESS/FAILED
|
||||
|
||||
#### Load 阶段 - 数据拉取
|
||||
|
||||
**目的**:从 API 获取数据,创建 SyncNode 放入 collection
|
||||
|
||||
| 阶段 | HTTP 操作 | 成功行为 | 失败行为 | 节点状态 |
|
||||
|------|----------|---------|---------|---------|
|
||||
| 1. 调用 load() | GET /api/list | 返回数据列表 | 返回空列表或抛异常 | - |
|
||||
| 2. 创建节点 | - | 为每条数据创建 SyncNode | 不创建节点 | PENDING |
|
||||
|
||||
**代码示例**:
|
||||
```python
|
||||
async def load(self, collection: DataCollection) -> List[dict]:
|
||||
"""加载数据 - GET 阶段不涉及状态转换"""
|
||||
try:
|
||||
response = await self.api_client.get("project/list")
|
||||
if response.status_code == 200:
|
||||
data_list = response.json().get("list", [])
|
||||
# 返回数据,由 DataSource 创建 PENDING 节点
|
||||
return data_list
|
||||
else:
|
||||
# 失败:返回空列表,不创建节点
|
||||
logger.error(f"Load failed: {response.status_code}")
|
||||
return []
|
||||
except Exception as e:
|
||||
logger.error(f"Load exception: {e}")
|
||||
return [] # 或者抛出异常,由调用方处理
|
||||
```
|
||||
|
||||
#### Mutation 请求(POST/PUT/DELETE) - 执行阶段
|
||||
|
||||
**状态变化时机**:
|
||||
1. **执行前**:DataSource 设置 `node.status = IN_PROGRESS`
|
||||
2. **Handler 执行**:内部可能重试,最终返回 SUCCESS/FAILED/IN_PROGRESS
|
||||
3. **轮询完成**:poll() 返回 SUCCESS/FAILED
|
||||
|
||||
| 阶段 | Push Log | TaskStatus | SyncStatus | 说明 |
|
||||
|------|---------|-----------|-----------|------|
|
||||
| 执行前 | - | - | PENDING → IN_PROGRESS | DataSource 设置 |
|
||||
| 提交 | pending | IN_PROGRESS | IN_PROGRESS | 任务已提交 |
|
||||
| 轮询 | processing | IN_PROGRESS | IN_PROGRESS | 后端处理中 |
|
||||
| 成功 | success | SUCCESS | SUCCESS | 同步完成 |
|
||||
| 失败 | failed | FAILED | FAILED | 同步失败 |
|
||||
|
||||
**示例**:
|
||||
```python
|
||||
async def create(self, node: SyncNode) -> TaskResult:
|
||||
"""Handler 内部可重试,最终返回确定结果"""
|
||||
response = await self.api_client.post(url, node.data)
|
||||
if response.status_code == 202:
|
||||
return TaskResult.in_progress(task_id=response.json()["push_id"])
|
||||
else:
|
||||
return TaskResult.failed(error=f"HTTP {response.status_code}")
|
||||
|
||||
async def poll(self, node: SyncNode, task_id: str) -> TaskResult:
|
||||
push_logs = await self.api_client.get_push_logs([task_id])
|
||||
status = push_logs.get(task_id, {}).get("status")
|
||||
if status == "success":
|
||||
return TaskResult.success(data_id=self.extract_created_id(push_logs[task_id]))
|
||||
elif status == "failed":
|
||||
return TaskResult.failed(error="Backend processing failed")
|
||||
else:
|
||||
return TaskResult.in_progress(task_id=task_id)
|
||||
```
|
||||
|
||||
### 4.2 状态转换完整流程
|
||||
|
||||
```
|
||||
Load 阶段:
|
||||
Handler.load() → 返回数据列表 → DataSource 创建 PENDING 节点
|
||||
|
||||
执行阶段(同步操作):
|
||||
DataSource: node.status = IN_PROGRESS
|
||||
→ Handler.create() → TaskResult.success/failed()
|
||||
→ DataSource: node.status = SUCCESS/FAILED
|
||||
|
||||
执行阶段(异步操作):
|
||||
DataSource: node.status = IN_PROGRESS
|
||||
→ Handler.create() → TaskResult.in_progress(push_id)
|
||||
→ DataSource 轮询: Handler.poll(push_id)
|
||||
→ TaskResult.success/failed()
|
||||
→ DataSource: node.status = SUCCESS/FAILED
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- Handler 负责重试,DataSource 只处理最终结果
|
||||
- 不同业务可在 BaseApiHandler._execute_with_retry 中自定义重试策略
|
||||
- FileDataSource 和 ApiDataSource 使用相同的状态枚举和转换逻辑
|
||||
|
||||
### 4.3 Push Log 状态机
|
||||
|
||||
```
|
||||
pending → processing → success/failed
|
||||
```
|
||||
|
||||
- 轮询间隔:0.5秒
|
||||
- 超时:30秒
|
||||
- 成功:提取 created_id
|
||||
- 失败:获取 error_message
|
||||
|
||||
### 4.4 状态总结表
|
||||
|
||||
**Load 阶段(数据拉取)**:
|
||||
|
||||
| HTTP 操作 | 响应码 | 行为 | 创建节点 | 节点状态 | 说明 |
|
||||
|---------|-------|-----|---------|---------|------|
|
||||
| GET /list | 200 | 返回数据列表 | ✅ 是 | PENDING | 等待后续 bind/create/update |
|
||||
| GET /list | 4xx/5xx | 返回空列表 | ❌ 否 | - | 不创建节点 |
|
||||
|
||||
**执行阶段(POST/PUT/DELETE)**:
|
||||
|
||||
| HTTP 操作 | 响应码 | Push Log | TaskStatus | SyncStatus | 说明 |
|
||||
|---------|-------|---------|-----------|-----------|------|
|
||||
| POST/PUT | 202 | pending | IN_PROGRESS | IN_PROGRESS | 异步开始 |
|
||||
| - | - | processing | IN_PROGRESS | IN_PROGRESS | 异步处理中 |
|
||||
| - | - | success | SUCCESS | SUCCESS | 异步成功 |
|
||||
| - | - | failed | FAILED | FAILED | 异步失败 |
|
||||
| - | - | timeout | FAILED | FAILED | 轮询超时 |
|
||||
|
||||
## 5. Context 机制
|
||||
|
||||
### 5.1 Context 的作用
|
||||
|
||||
Context 是 SyncNode 的字典字段,用于存储业务数据之外的上下文信息,例如:
|
||||
- `project_id`: 当前对象所属的项目ID
|
||||
- `contract_id`: 合同变更所属的合同ID
|
||||
- `parent_id`: 父对象ID
|
||||
- 其他 API 调用需要但 schema 中没有的信息
|
||||
|
||||
### 5.2 Context 使用流程
|
||||
|
||||
**场景:加载合同数据**
|
||||
|
||||
1. **Handler.load()** 从 self._collection 获取所有 project
|
||||
2. 遍历每个 project,调用 `GET contract/list?project_id=xxx`
|
||||
3. 为每个返回的 contract 数据添加临时标记 `_context = {"project_id": xxx}`
|
||||
4. **Handler.create_node()** 创建 SyncNode 时,提取 `_context` 并设置到 `node.context`
|
||||
5. **Handler.update()** 更新时,从 `node.context["project_id"]` 获取 project_id 并添加到请求数据
|
||||
|
||||
### 5.3 Context 传递规则
|
||||
|
||||
- 父 → 子:从依赖的父节点继承 context
|
||||
- 横向传递:同级节点不共享 context
|
||||
- 更新时使用:从 context 提取必要信息添加到请求 payload
|
||||
|
||||
## 6. 智能 API 路由
|
||||
|
||||
### 6.1 路由策略
|
||||
|
||||
根据节点数据的字段,自动选择正确的 API endpoint:
|
||||
|
||||
**方案1:字段匹配**
|
||||
- 检查 node.data 中的字段集合
|
||||
- 匹配预定义的 endpoint → required_fields 映射表
|
||||
- 选择第一个匹配的 endpoint
|
||||
|
||||
**方案2:Schema 类型**
|
||||
- 根据 node.schema 的类型
|
||||
- 查找 schema_type → endpoint 映射表
|
||||
|
||||
**默认规则**:
|
||||
- CREATE: `{node_type}`
|
||||
- UPDATE: 子类重写 `_select_update_endpoint()`
|
||||
- DELETE: `{node_type}`
|
||||
|
||||
### 6.2 Project 示例
|
||||
|
||||
Project 有多个更新接口:
|
||||
- `project/key_constraints` - 需要字段:key_constraints, key_constraints_remark
|
||||
- `project/complete_investment` - 需要字段:complete_investment
|
||||
- `project/dynamic_investment` - 需要字段:dynamic_investment
|
||||
- `project/plan_construction` - 需要字段:plan_construction_capacity, plan_construction_date
|
||||
- ... 等
|
||||
|
||||
Handler 定义映射表,根据实际数据字段自动选择。
|
||||
|
||||
## 7. 依赖数据获取
|
||||
|
||||
### 7.1 获取模式
|
||||
|
||||
Handler 通过 `collection.filter(node_type="xxx")` 获取依赖数据:
|
||||
|
||||
**加载顺序**(按依赖关系):
|
||||
1. Project(无依赖)
|
||||
2. Contract(依赖 Project)
|
||||
3. Contract Change(依赖 Project + Contract)
|
||||
|
||||
### 7.2 数据流
|
||||
|
||||
```
|
||||
Pipeline
|
||||
→ 按拓扑序加载
|
||||
→ ProjectHandler.load()
|
||||
→ GET project/list
|
||||
→ 创建 ProjectSyncNode
|
||||
→ ContractHandler.load()
|
||||
→ collection.filter(node_type="project")
|
||||
→ 遍历 project,GET contract/list?project_id=xxx
|
||||
→ 创建 ContractSyncNode,设置 context["project_id"]
|
||||
→ ContractChangeHandler.load()
|
||||
→ collection.filter(node_type="contract")
|
||||
→ 遍历 contract,从 context 获取 project_id
|
||||
→ GET contract_change/list?project_id=xxx&contract_id=yyy
|
||||
→ 创建节点,设置 context
|
||||
```
|
||||
|
||||
## 8. 实现计划
|
||||
|
||||
### Phase 1: HTTP 通信层
|
||||
- 实现 **ApiClient** 类
|
||||
- HTTP Client 封装(httpx.AsyncClient)
|
||||
- 签名生成(_generate_signature)
|
||||
- 统一请求方法(get/post/put/delete)
|
||||
- **批量 Push Log 查询**(get_push_logs,单个也传列表)
|
||||
- ~~wait_for_push_log~~(不实现,由 DataSource 调用 poll)
|
||||
|
||||
### Phase 2: DataSource 协调层
|
||||
- 实现 **ApiDataSource** 类
|
||||
- 持有 ApiClient 实例
|
||||
- Handler 注册和管理
|
||||
- 实现 DataSource 接口(load_all, execute_batch)
|
||||
- 注入 api_client 到 Handler
|
||||
- 实现轮询逻辑(_poll_async_tasks)
|
||||
|
||||
### Phase 3: Handler 基类
|
||||
- 实现 **BaseApiHandler** 类
|
||||
- load/create/update/delete/poll 方法
|
||||
- 使用 self.api_client 发送请求
|
||||
- **extract_created_id**(子类可重写)
|
||||
- **_execute_with_retry**(可选,子类可重写重试策略)
|
||||
- Context 管理
|
||||
|
||||
### Phase 4: 业务验证
|
||||
- 实现 **ProjectApiHandler**(无依赖,简单场景)
|
||||
- 实现 load:GET project/list
|
||||
- 实现 create:POST project
|
||||
- 实现 poll:查询 push_log
|
||||
- 实现 **ContractApiHandler**(依赖 Project,验证 context)
|
||||
- 实现 load:遍历 project,GET contract/list?project_id=xxx
|
||||
- 设置 context["project_id"]
|
||||
- 编写测试验证设计
|
||||
|
||||
### Phase 5: 完善功能
|
||||
- 批量 Push Log 查询优化(等待后端实现批量接口)
|
||||
- 超时控制(可配置)
|
||||
- 请求日志和调试
|
||||
|
||||
### Phase 6: 推广
|
||||
- 实现剩余业务 Handler
|
||||
- 性能优化(并发控制)
|
||||
- 文档和示例
|
||||
|
||||
## 9. 与现有系统集成
|
||||
|
||||
**调用关系**:
|
||||
```
|
||||
Pipeline
|
||||
↓
|
||||
ApiDataSource (持有 ApiClient)
|
||||
↓
|
||||
BaseApiHandler (使用 api_client)
|
||||
↓
|
||||
ApiClient (发送 HTTP 请求)
|
||||
```
|
||||
|
||||
**职责分离**:
|
||||
- **ApiClient**: 纯粹的 HTTP 通信,无业务逻辑
|
||||
- **ApiDataSource**: 协调 Handler,管理执行流程
|
||||
- **BaseApiHandler**: 业务逻辑,调用 ApiClient 完成网络操作
|
||||
- **具体 Handler**: 实现特定业务的 load/create/update/delete
|
||||
|
||||
**优点**:
|
||||
- ApiClient 和 Handler 解耦,避免循环依赖
|
||||
- Handler 通过 self.api_client 访问 HTTP 功能
|
||||
- DataSource 统一管理 ApiClient 生命周期
|
||||
- Handler 内部灵活控制重试策略
|
||||
|
||||
## 10. 关键优势
|
||||
|
||||
1. **简化架构**:去掉 Repository 层,代码量减少 50%
|
||||
2. **职责清晰**:
|
||||
- ApiClient:HTTP 通信
|
||||
- DataSource:协调和轮询
|
||||
- Handler:业务逻辑和重试
|
||||
3. **重试灵活**:Handler 内部实现,不同业务可自定义策略
|
||||
4. **状态清晰**:Load 阶段创建 PENDING 节点,执行阶段明确状态转换
|
||||
5. **批量优化**:Push Log 批量查询,减少 HTTP 请求
|
||||
6. **易于扩展**:新业务只需实现 Handler,复用 Client 和 DataSource
|
||||
7. **易于测试**:ApiClient 可 mock,Handler 独立测试
|
||||
|
||||
## 11. 设计改进总结
|
||||
|
||||
| 改进点 | 初始设计 | 最终设计 | 理由 |
|
||||
|-------|---------|---------|------|
|
||||
| Push Log 查询 | get_push_log(id) | get_push_logs([ids]) | 批量查询 |
|
||||
| 轮询逻辑 | wait_for_push_log 在 Client | 移除,DataSource 调用 poll | 职责清晰 |
|
||||
| created_id 提取 | 在 Client | 在 Handler 基类 | 业务差异 |
|
||||
| 重试逻辑 | 在 DataSource | **在 Handler** | 业务灵活性 |
|
||||
| Load 状态 | GET 成功 → SUCCESS | GET 成功 → PENDING | Load ≠ 同步完成 |
|
||||
| 执行状态 | 不明确 | 执行前设置 IN_PROGRESS | 状态清晰 |
|
||||
7. **易于测试**:ApiClient 可以 mock,Handler 单独测试业务逻辑
|
||||
|
||||
## 12. 使用示例
|
||||
|
||||
### 12.1 基本使用流程
|
||||
|
||||
```python
|
||||
# 1. 创建 DataSource
|
||||
datasource = ApiDataSource(
|
||||
base_url="https://api.example.com",
|
||||
uid="user123",
|
||||
secret="secret_key"
|
||||
)
|
||||
|
||||
# 2. 初始化(必须调用)
|
||||
await datasource.initialize()
|
||||
|
||||
# 3. 注册 Handler
|
||||
datasource.register_handler(ProjectApiHandler())
|
||||
datasource.register_handler(ContractApiHandler())
|
||||
|
||||
# 4. 创建 Collection
|
||||
collection = DataCollection()
|
||||
|
||||
# 5. 加载数据(自动处理异常,不会抛出)
|
||||
await datasource.load_all(collection, order=["project", "contract"])
|
||||
|
||||
# 6. 执行同步(自动处理异常,不会抛出)
|
||||
await datasource.sync_all(collection, order=["project", "contract"])
|
||||
|
||||
# 7. 关闭连接(必须调用)
|
||||
await datasource.close()
|
||||
```
|
||||
|
||||
### 12.2 异常处理说明
|
||||
|
||||
**设计原则**:
|
||||
- ✅ **load_all 和 sync_all 不会抛出异常**
|
||||
- ✅ **Handler 的 create/update/delete 捕获所有 HTTP 异常**
|
||||
- ✅ **所有错误转换为状态(SyncStatus.FAILED)和错误信息(node.error)**
|
||||
|
||||
**为什么不需要 try-finally?**
|
||||
|
||||
```python
|
||||
# ❌ 不需要这样做
|
||||
try:
|
||||
await datasource.load_all(collection, order=["project"])
|
||||
finally:
|
||||
await datasource.close()
|
||||
|
||||
# ✅ 直接调用即可
|
||||
await datasource.initialize()
|
||||
await datasource.load_all(collection, order=["project"]) # 内部已处理异常
|
||||
await datasource.sync_all(collection, order=["project"]) # 内部已处理异常
|
||||
await datasource.close()
|
||||
```
|
||||
|
||||
**异常处理机制**:
|
||||
|
||||
1. **load_all 异常处理**:
|
||||
```python
|
||||
# 加载某个类型失败,记录错误但继续处理其他类型
|
||||
for node_type in order:
|
||||
try:
|
||||
raw_items = await handler.load(collection)
|
||||
# ... 创建节点
|
||||
except Exception as e:
|
||||
print(f"Error loading {node_type}: {e}")
|
||||
# 继续处理下一个类型
|
||||
```
|
||||
|
||||
2. **sync_all 异常处理**:
|
||||
```python
|
||||
# Handler 返回的异常已被捕获转为 TaskResult
|
||||
for node in nodes:
|
||||
try:
|
||||
result = await handler.create(node) # Handler 内部捕获异常
|
||||
# 根据 result.status 更新节点状态
|
||||
except Exception as e:
|
||||
# DataSource 的最后保护
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = str(e)
|
||||
```
|
||||
|
||||
3. **Handler 异常处理**:
|
||||
```python
|
||||
async def create(self, node: SyncNode) -> TaskResult:
|
||||
try:
|
||||
# 生成参数
|
||||
push_id = self._generate_push_id()
|
||||
data = {..., "push_id": push_id, "biz_id": self._generate_biz_id(node)}
|
||||
|
||||
# 调用 API
|
||||
response = await self.api_client.post("/api/v2/project", data)
|
||||
|
||||
# 返回成功
|
||||
return TaskResult(status=TaskStatus.SUCCESS, data_id=response['data']['id'])
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
# HTTP 错误(4xx, 5xx)
|
||||
return TaskResult(status=TaskStatus.FAILED, error=f"HTTP {e.response.status_code}: {e}")
|
||||
except httpx.NetworkError as e:
|
||||
# 网络错误
|
||||
return TaskResult(status=TaskStatus.FAILED, error=f"Network error: {e}")
|
||||
except Exception as e:
|
||||
# 其他异常
|
||||
return TaskResult(status=TaskStatus.FAILED, error=f"Unexpected error: {e}")
|
||||
```
|
||||
|
||||
### 12.3 Pipeline 集成示例
|
||||
|
||||
```python
|
||||
async def sync_pipeline(datasource: ApiDataSource):
|
||||
"""同步流程编排"""
|
||||
|
||||
# 初始化
|
||||
await datasource.initialize()
|
||||
|
||||
# 创建 Collection
|
||||
collection = DataCollection()
|
||||
|
||||
# 执行同步流程(所有错误都被内部处理)
|
||||
await datasource.load_all(collection, order=["project", "contract", "material"])
|
||||
await datasource.sync_all(collection, order=["project", "contract", "material"])
|
||||
|
||||
# 检查结果
|
||||
failed_nodes = collection.filter(status=SyncStatus.FAILED)
|
||||
if failed_nodes:
|
||||
print(f"Failed nodes: {len(failed_nodes)}")
|
||||
for node in failed_nodes:
|
||||
print(f" - {node.node_type}:{node.node_id}: {node.error}")
|
||||
|
||||
# 清理
|
||||
await datasource.close()
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- ✅ 不需要 try-except 包裹 load_all/sync_all
|
||||
- ✅ 通过检查节点状态判断成功/失败
|
||||
- ✅ 错误信息保存在 node.error 中
|
||||
- ✅ Pipeline 专注于流程编排,不处理异常细节
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
# DataSource + Handler 架构设计 V2
|
||||
|
||||
## 核心原则
|
||||
|
||||
### **职责分离**
|
||||
|
||||
```text
|
||||
Strategy (业务逻辑层)
|
||||
↓ 设置 action, 完成 ID 映射
|
||||
DataSource (状态管理 + 编排层)
|
||||
↓ 调用 Handler, 管理状态流转
|
||||
Handler (纯执行层)
|
||||
↓ 调用后端 API, 返回结果
|
||||
Backend API
|
||||
```
|
||||
|
||||
### **关键设计决策**
|
||||
|
||||
1. **ID 映射在 Strategy 完成** ✅
|
||||
- `Strategy.create()` / `Strategy.update()` 时,已将依赖字段的本地 ID 替换为远程 ID
|
||||
- DataSource 拿到的 `node.data` 已经是映射好的数据
|
||||
- Handler 直接使用 `node.data`,不需要关心 ID 映射
|
||||
|
||||
2. **状态管理在 DataSource** ✅
|
||||
- 所有 `node.status` 的转换由 DataSource 负责
|
||||
- Handler 只返回 `TaskResult`(成功/失败/进行中)
|
||||
- DataSource 根据 `TaskResult` 更新 `node.status`
|
||||
|
||||
3. **Handler 只负责执行** ✅
|
||||
- 调用后端 API(load/create/update/delete)
|
||||
- 返回执行结果(TaskResult)
|
||||
- 提供异步任务轮询(poll_tasks)
|
||||
- 提供数据质量检查(validate)
|
||||
|
||||
---
|
||||
|
||||
## Handler 接口设计
|
||||
|
||||
### **核心方法**
|
||||
|
||||
```python
|
||||
class NodeHandler(Protocol[T]):
|
||||
# ===== 数据加载 =====
|
||||
async def load(self, collection: Optional[DataCollection] = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
从后端加载全部数据
|
||||
|
||||
Args:
|
||||
collection: Collection 上下文(可选,用于依赖查询)
|
||||
|
||||
Returns:
|
||||
原始数据列表
|
||||
|
||||
示例:
|
||||
# Contract Handler(依赖 Project)
|
||||
async def load(self, collection=None):
|
||||
# 从 collection 获取 project 列表
|
||||
if collection:
|
||||
projects = collection.filter(node_type="project")
|
||||
project_ids = [p.data_id for p in projects if p.data_id]
|
||||
else:
|
||||
project_ids = []
|
||||
|
||||
# 只加载这些项目的合同
|
||||
response = await self.api.get_contracts(project_ids=project_ids)
|
||||
return response["data"]
|
||||
"""
|
||||
|
||||
# ===== 数据操作 =====
|
||||
async def create(self, node: SyncNode[T]) -> TaskResult:
|
||||
"""
|
||||
创建节点
|
||||
|
||||
注意:node.data 已经过 ID 映射,直接使用即可
|
||||
|
||||
Returns:
|
||||
TaskResult:
|
||||
- SUCCESS: 同步完成,返回 data_id
|
||||
- IN_PROGRESS: 异步任务,返回 task_id
|
||||
- FAILED: 失败,返回 error
|
||||
|
||||
示例:
|
||||
# 同步接口
|
||||
async def create(self, node):
|
||||
try:
|
||||
response = await self.api.create_contract(node.data)
|
||||
return TaskResult.success(data_id=response["id"])
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
|
||||
# 异步接口
|
||||
async def create(self, node):
|
||||
try:
|
||||
response = await self.api.submit_contract_async(node.data)
|
||||
return TaskResult.in_progress(task_id=response["task_id"])
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
"""
|
||||
|
||||
async def update(self, node: SyncNode[T]) -> TaskResult:
|
||||
"""更新节点(同 create)"""
|
||||
|
||||
async def delete(self, node: SyncNode[T]) -> TaskResult:
|
||||
"""删除节点(同 create)"""
|
||||
|
||||
# ===== 异步任务轮询 =====
|
||||
async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
|
||||
"""
|
||||
批量轮询异步任务状态
|
||||
|
||||
Args:
|
||||
task_ids: 任务 ID 列表
|
||||
|
||||
Returns:
|
||||
{task_id: TaskResult} 字典
|
||||
|
||||
示例:
|
||||
async def poll_tasks(self, task_ids):
|
||||
response = await self.api.batch_query_tasks(task_ids)
|
||||
results = {}
|
||||
for task in response["tasks"]:
|
||||
if task["status"] == "completed":
|
||||
results[task["id"]] = TaskResult.success(
|
||||
data_id=task["result"]["contract_id"]
|
||||
)
|
||||
elif task["status"] == "failed":
|
||||
results[task["id"]] = TaskResult.failed(
|
||||
error=task["error"]
|
||||
)
|
||||
else: # running
|
||||
results[task["id"]] = TaskResult.in_progress(
|
||||
task_id=task["id"]
|
||||
)
|
||||
return results
|
||||
"""
|
||||
|
||||
# ===== 数据质量检查 =====
|
||||
async def validate(self, data: Dict[str, Any]) -> ValidationResult:
|
||||
"""
|
||||
数据质量检查
|
||||
|
||||
Args:
|
||||
data: 原始数据
|
||||
|
||||
Returns:
|
||||
ValidationResult(是否有效 + 错误列表)
|
||||
|
||||
示例:
|
||||
async def validate(self, data):
|
||||
errors = []
|
||||
if not data.get("code"):
|
||||
errors.append("合同编码为空")
|
||||
if not data.get("project_id"):
|
||||
errors.append("项目 ID 为空")
|
||||
|
||||
return ValidationResult(
|
||||
is_valid=len(errors) == 0,
|
||||
errors=errors
|
||||
)
|
||||
"""
|
||||
|
||||
# ===== 辅助方法 =====
|
||||
def extract_id(self, data: Dict[str, Any]) -> str:
|
||||
"""从原始数据提取 ID"""
|
||||
|
||||
def create_node(self, data: Dict[str, Any]) -> SyncNode[T]:
|
||||
"""从原始数据创建 SyncNode"""
|
||||
```
|
||||
|
||||
### **TaskResult 设计**
|
||||
|
||||
```python
|
||||
class TaskStatus(Enum):
|
||||
SUCCESS = "success" # 同步完成
|
||||
FAILED = "failed" # 失败
|
||||
IN_PROGRESS = "in_progress" # 异步任务进行中
|
||||
|
||||
|
||||
class TaskResult:
|
||||
def __init__(
|
||||
self,
|
||||
status: TaskStatus,
|
||||
data_id: Optional[str] = None, # 成功时返回的 ID
|
||||
task_id: Optional[str] = None, # 异步任务 ID
|
||||
error: Optional[str] = None, # 失败原因
|
||||
metadata: Optional[Dict] = None # 其他元数据
|
||||
):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def success(cls, data_id: Optional[str] = None) -> TaskResult:
|
||||
"""创建成功结果"""
|
||||
|
||||
@classmethod
|
||||
def failed(cls, error: str) -> TaskResult:
|
||||
"""创建失败结果"""
|
||||
|
||||
@classmethod
|
||||
def in_progress(cls, task_id: str) -> TaskResult:
|
||||
"""创建进行中结果"""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DataSource 接口设计
|
||||
|
||||
### **接口方法**
|
||||
|
||||
```python
|
||||
class BaseDataSource(ABC):
|
||||
# ===== Handler 管理 =====
|
||||
def register_handler(self, handler: NodeHandler) -> None:
|
||||
"""注册 Handler"""
|
||||
|
||||
def get_handler(self, node_type: str) -> NodeHandler:
|
||||
"""获取 Handler"""
|
||||
|
||||
# ===== 数据加载 =====
|
||||
async def load_all(
|
||||
self,
|
||||
order: List[str]
|
||||
) -> None:
|
||||
"""
|
||||
按依赖顺序加载所有数据
|
||||
|
||||
注意:调用前需先 set_collection()
|
||||
|
||||
Args:
|
||||
order: 节点类型顺序(如 ["project", "contract", "construction"])
|
||||
|
||||
工作流程:
|
||||
1. 按顺序遍历每个节点类型
|
||||
2. 调用 Handler.load()
|
||||
3. Handler 可以从 self._collection 查询依赖节点
|
||||
4. 使用 Handler.create_node() 创建 SyncNode
|
||||
5. 添加到 Collection
|
||||
"""
|
||||
|
||||
# ===== 同步执行 =====
|
||||
async def sync_all(
|
||||
self,
|
||||
order: List[str]
|
||||
) -> None:
|
||||
"""
|
||||
按依赖顺序执行同步
|
||||
|
||||
流程:
|
||||
1. 按顺序遍历每个节点类型
|
||||
2. 筛选需要同步的节点(status=PENDING, action!=NONE)
|
||||
3. 调用 Handler 的 create/update/delete
|
||||
4. 根据 TaskResult 更新节点状态
|
||||
5. 处理异步任务轮询
|
||||
"""
|
||||
|
||||
# ===== 统计信息 =====
|
||||
def get_sync_summary(self, collection: DataCollection) -> Dict[str, Any]:
|
||||
"""获取同步统计信息"""
|
||||
```
|
||||
|
||||
### **状态流转逻辑**
|
||||
|
||||
```python
|
||||
async def _sync_nodes(self, handler, nodes):
|
||||
async_tasks = {} # {node_id: task_id}
|
||||
|
||||
for node in nodes:
|
||||
# 1. 跳过不需要处理的节点
|
||||
if node.action == SyncAction.NONE:
|
||||
continue
|
||||
|
||||
# 2. 跳过异常状态节点
|
||||
if node.binding_status in [DEPENDENCY_ERROR, ABNORMAL, WARNING]:
|
||||
node.status = SyncStatus.SKIPPED
|
||||
continue
|
||||
|
||||
# 3. 只处理 PENDING 节点
|
||||
if node.status != SyncStatus.PENDING:
|
||||
continue
|
||||
|
||||
# 4. 执行操作
|
||||
try:
|
||||
node.status = SyncStatus.IN_PROGRESS
|
||||
|
||||
if node.action == SyncAction.CREATE:
|
||||
result = await handler.create(node)
|
||||
elif node.action == SyncAction.UPDATE:
|
||||
result = await handler.update(node)
|
||||
elif node.action == SyncAction.DELETE:
|
||||
result = await handler.delete(node)
|
||||
|
||||
# 5. 处理结果
|
||||
if result.status == TaskStatus.SUCCESS:
|
||||
node.status = SyncStatus.SUCCESS
|
||||
if result.data_id:
|
||||
node.data_id = result.data_id # 回填 ID
|
||||
|
||||
elif result.status == TaskStatus.FAILED:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = result.error
|
||||
|
||||
elif result.status == TaskStatus.IN_PROGRESS:
|
||||
async_tasks[node.node_id] = result.task_id
|
||||
|
||||
except Exception as e:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = str(e)
|
||||
|
||||
# 6. 轮询异步任务
|
||||
if async_tasks:
|
||||
await self._poll_async_tasks(handler, nodes, async_tasks)
|
||||
```
|
||||
|
||||
### **异步任务轮询**
|
||||
|
||||
```python
|
||||
async def _poll_async_tasks(self, handler, nodes, async_tasks):
|
||||
node_map = {n.node_id: n for n in nodes}
|
||||
|
||||
max_retries = poll_max_retries # 默认轮询 1 次,可配置
|
||||
retry_count = 0
|
||||
|
||||
while async_tasks and retry_count < max_retries:
|
||||
# 批量查询
|
||||
task_ids = list(async_tasks.values())
|
||||
results = await handler.poll_tasks(task_ids)
|
||||
|
||||
# 处理结果
|
||||
for node_id, task_id in list(async_tasks.items()):
|
||||
if task_id not in results:
|
||||
continue
|
||||
|
||||
result = results[task_id]
|
||||
node = node_map[node_id]
|
||||
|
||||
if result.status == TaskStatus.SUCCESS:
|
||||
node.status = SyncStatus.SUCCESS
|
||||
if result.data_id:
|
||||
node.data_id = result.data_id
|
||||
async_tasks.pop(node_id)
|
||||
|
||||
elif result.status == TaskStatus.FAILED:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = result.error
|
||||
async_tasks.pop(node_id)
|
||||
|
||||
# 还有未完成任务,等待后重试
|
||||
if async_tasks:
|
||||
await asyncio.sleep(2)
|
||||
retry_count += 1
|
||||
|
||||
# 超时未完成的任务标记为失败
|
||||
for node_id in async_tasks:
|
||||
node = node_map[node_id]
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = "Async task timeout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整流程示例
|
||||
|
||||
### **Pipeline 编排**
|
||||
|
||||
```python
|
||||
# Stage 0: 初始化
|
||||
collection = DataCollection()
|
||||
datasource = ApiDataSource(api_client)
|
||||
|
||||
# 注册 Handler
|
||||
datasource.register_handler(ProjectNodeHandler(api_client))
|
||||
datasource.register_handler(ContractNodeHandler(api_client))
|
||||
|
||||
# Stage 1: 加载数据
|
||||
datasource.set_collection(collection)
|
||||
await datasource.load_all(
|
||||
order=["project", "contract"] # 依赖顺序
|
||||
)
|
||||
|
||||
# Stage 2: Strategy 执行
|
||||
for strategy in [project_strategy, contract_strategy]:
|
||||
await strategy.bind() # 设置 binding_status
|
||||
await strategy.create() # 设置 action=CREATE + ID 映射
|
||||
await strategy.update() # 设置 action=UPDATE + ID 映射
|
||||
await strategy.pre_sync_check()
|
||||
|
||||
# Stage 3: 物理同步
|
||||
await datasource.sync_all(
|
||||
order=["project", "contract"]
|
||||
)
|
||||
|
||||
# Stage 4: 检查结果
|
||||
summary = datasource.get_sync_summary(collection)
|
||||
print(f"Success: {summary['success']}, Failed: {summary['failed']}")
|
||||
```
|
||||
|
||||
### **Contract Handler 实现**
|
||||
|
||||
```python
|
||||
class ContractNodeHandler(BaseNodeHandler[ContractResponse]):
|
||||
def __init__(self, api_client):
|
||||
super().__init__(
|
||||
node_type="contract",
|
||||
node_class=ContractSyncNode,
|
||||
schema=ContractResponse
|
||||
)
|
||||
self.api = api_client
|
||||
|
||||
async def load(self):
|
||||
"""加载合同(依赖 Project)"""
|
||||
if self._collection:
|
||||
projects = self._collection.filter(node_type="project")
|
||||
project_ids = [p.data_id for p in projects if p.data_id]
|
||||
else:
|
||||
project_ids = []
|
||||
|
||||
response = await self.api.get_contracts(project_ids=project_ids)
|
||||
return response["data"]
|
||||
|
||||
async def create(self, node):
|
||||
"""创建合同(异步接口)"""
|
||||
try:
|
||||
# node.data 已经过 ID 映射,直接使用
|
||||
response = await self.api.create_contract_async(node.data)
|
||||
|
||||
if response.get("async"):
|
||||
return TaskResult.in_progress(task_id=response["task_id"])
|
||||
else:
|
||||
return TaskResult.success(data_id=response["id"])
|
||||
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
|
||||
async def update(self, node):
|
||||
"""更新合同(同步接口)"""
|
||||
try:
|
||||
response = await self.api.update_contract(node.data_id, node.data)
|
||||
return TaskResult.success()
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
|
||||
async def poll_tasks(self, task_ids):
|
||||
"""轮询异步任务"""
|
||||
response = await self.api.batch_query_tasks(task_ids)
|
||||
results = {}
|
||||
for task in response["tasks"]:
|
||||
if task["status"] == "completed":
|
||||
results[task["id"]] = TaskResult.success(
|
||||
data_id=task["result"]["contract_id"]
|
||||
)
|
||||
elif task["status"] == "failed":
|
||||
results[task["id"]] = TaskResult.failed(error=task["error"])
|
||||
else:
|
||||
results[task["id"]] = TaskResult.in_progress(task_id=task["id"])
|
||||
return results
|
||||
|
||||
async def validate(self, data):
|
||||
"""数据质量检查"""
|
||||
errors = []
|
||||
if not data.get("code"):
|
||||
errors.append("合同编码为空")
|
||||
if not data.get("project_id"):
|
||||
errors.append("项目 ID 为空")
|
||||
|
||||
return ValidationResult(is_valid=len(errors) == 0, errors=errors)
|
||||
|
||||
def extract_id(self, data):
|
||||
return data["id"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心优势
|
||||
|
||||
### **1. 职责清晰**
|
||||
|
||||
- **Strategy**: 业务逻辑 + ID 映射
|
||||
- **DataSource**: 状态管理 + 编排
|
||||
- **Handler**: 纯执行(后端 API 调用)
|
||||
|
||||
### **2. ID 映射前置**
|
||||
|
||||
- ID 映射在 Strategy 完成,DataSource 和 Handler 无需关心
|
||||
- `node.data` 已经是映射好的数据,直接使用
|
||||
|
||||
### **3. 状态统一管理**
|
||||
|
||||
- 所有状态流转由 DataSource 负责
|
||||
- Handler 只返回结果,不改变节点状态
|
||||
|
||||
### **4. 异步任务支持**
|
||||
|
||||
- Handler 返回 `TaskResult.in_progress(task_id)`
|
||||
- DataSource 自动轮询直到完成
|
||||
|
||||
### **5. 数据质量保障**
|
||||
|
||||
|
||||
- Handler 提供 `validate()` 方法
|
||||
- DataSource 在加载时检查数据质量
|
||||
|
||||
### **6. 易于测试**
|
||||
|
||||
- Handler 可以 Mock(返回假 TaskResult)
|
||||
- DataSource 可以单独测试状态流转逻辑
|
||||
- Strategy 可以单独测试 ID 映射逻辑
|
||||
|
||||
---
|
||||
|
||||
## 与现有架构的兼容性
|
||||
|
||||
完全符合 [架构分层设计.md](./架构分层设计.md) 的四层模型:
|
||||
|
||||
1. **Common 层**: SyncNode, DataCollection, BindingManager
|
||||
2. **Sync System 层**: SyncStrategy(负责 bind/create/update + ID 映射)
|
||||
3. **DataSource 层**: BaseDataSource + NodeHandler(状态管理 + 执行)
|
||||
4. **Pipeline 层**: 流程编排 + 依赖顺序
|
||||
|
||||
符合 [状态定义规范.md](./状态定义规范.md) 的状态流转逻辑。
|
||||
@@ -0,0 +1,150 @@
|
||||
# node_id / data_id / 持久化与生命周期说明
|
||||
|
||||
本文档说明同步系统中 `node_id` 与 `data_id` 的职责、生成时机、持久化行为,以及同步流程中“创建/绑定/回填”的完整生命周期。目标是避免“重复生成 node_id 导致绑定失效”的问题,并明确各层职责。
|
||||
|
||||
---
|
||||
|
||||
## 1. 基础概念
|
||||
|
||||
- **data_id**
|
||||
- 业务主键(来自数据源/远端系统的资源 ID)。
|
||||
- 在加载阶段通常已存在;在 CREATE 场景下初始为空,成功后由 DataSource 回填。
|
||||
|
||||
- **node_id**
|
||||
- 同步系统内部的**稳定标识符**(绑定与持久化的主键)。
|
||||
- 用于绑定表、持久化节点、依赖追踪等。
|
||||
- 设计目标:**跨同步周期稳定**,不能随每次加载而变化。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心结论(必须遵守)
|
||||
|
||||
1. **node_id 一旦建立,不应再被数据源“重新生成”。**
|
||||
- 绑定关系与持久化状态依赖 `node_id`;若每次加载都重新生成,会导致历史绑定失效。
|
||||
2. **加载阶段应先恢复 Collection(持久化节点),再加载 DataSource 数据。**
|
||||
- 数据源加载出的 `data_id` 应优先匹配已持久化的节点;匹配到则复用旧 `node_id`。
|
||||
3. **CREATE 场景允许临时/新建 node_id**,但必须通过后续回填与绑定更新保持一致性。
|
||||
|
||||
---
|
||||
|
||||
## 3. 正确的初始化/加载顺序
|
||||
|
||||
### 推荐流程(Pipeline 前半段)
|
||||
|
||||
1. **持久化恢复阶段**
|
||||
- 必须同时恢复 `node_id` 与 `data_id`(以及状态字段),否则无法建立稳定的映射关系。
|
||||
- Collection 可能为空,这属于合法情况。
|
||||
|
||||
2. **数据源加载阶段(DataSource.load_all)**
|
||||
- 对每一条业务数据(含 `data_id`):
|
||||
- **若 Collection 内已存在该 `data_id` 对应节点**:将数据写回原节点(保留旧 `node_id`)。
|
||||
- **若不存在**:由 **Collection** 生成新的 `node_id`,并创建新节点。
|
||||
|
||||
> 这样可避免“第二次同步时重建节点,导致旧绑定丢失”。
|
||||
|
||||
---
|
||||
|
||||
## 4. node_id 的来源与稳定性
|
||||
|
||||
### A. 持久化恢复阶段
|
||||
|
||||
- **恢复时必须包含 `node_id` 与 `data_id`**:
|
||||
- 两者成对恢复,才能保证后续 load 阶段按 `data_id` 命中旧节点。
|
||||
|
||||
### B. 数据源加载阶段
|
||||
|
||||
- **优先复用持久化 node_id**:
|
||||
- 通过 `data_id` 在 Collection 中查找并更新已有节点。
|
||||
- **仅在未知 data_id 时新建 node_id**:
|
||||
- 新节点 `node_id` 必须由 **Collection** 生成,而非 DataSource/Handler 直接拼接。
|
||||
|
||||
### C. 创建阶段(Strategy.create)
|
||||
|
||||
- 新建“目标端”节点时,**必须有 node_id**:
|
||||
- 用于写入 Collection、记录状态、建立临时绑定。
|
||||
- 成功后回填 `data_id`,**node_id 不变**。
|
||||
|
||||
---
|
||||
|
||||
## 5. data_id 的来源与回填
|
||||
|
||||
本节按阶段拆分说明 `data_id` 的来源与写回。
|
||||
|
||||
### A. 持久化恢复阶段
|
||||
|
||||
- `data_id` 从持久化数据中恢复(与 `node_id` 一起恢复)。
|
||||
|
||||
### B. 数据源加载阶段
|
||||
|
||||
- `data_id` 来自数据源原始数据(`id` / `_id`)。
|
||||
- 若命中已有节点,则仅更新数据与状态,不改变 `node_id`。
|
||||
|
||||
### C. 同步创建与轮询阶段
|
||||
|
||||
- CREATE 提交后,DataSource 从响应/轮询结果提取 `biz_id`。
|
||||
- 成功时回填到 `node.data_id`,并回写 `node.data` 的主键字段(仅 `id` / `_id`)。
|
||||
|
||||
### D. 持久化阶段
|
||||
|
||||
- 将更新后的 `node_id` / `data_id` / 状态字段持久化,供下次同步恢复使用。
|
||||
|
||||
---
|
||||
|
||||
## 6. 绑定与 node_id 的关系
|
||||
|
||||
- 绑定表的 key 为 `node_id`,绑定记录是 `local_node_id <-> remote_node_id`。
|
||||
- 因此:**node_id 必须稳定**,才能保证绑定长期有效。
|
||||
- 绑定可在创建前建立“临时关系”,但成功后不应更换 node_id。
|
||||
|
||||
---
|
||||
|
||||
## 7. 同步周期中的典型场景
|
||||
|
||||
### 场景 1:第一次同步(无持久化)
|
||||
- Collection 为空 → DataSource load 新节点 → 生成新 `node_id`。
|
||||
- Strategy bind / create / update 执行。
|
||||
- 持久化后,下次同步可复用 `node_id`。
|
||||
|
||||
### 场景 2:第二次同步(已有持久化)
|
||||
- 先恢复 Collection(已有 `node_id`)。
|
||||
- DataSource load 时按 `data_id` 匹配旧节点并更新数据。
|
||||
- 绑定关系仍有效。
|
||||
|
||||
### 场景 3:创建新数据(CREATE)
|
||||
- Strategy 产生目标端节点(`node_id` 新生成)。
|
||||
- DataSource 执行创建,回填 `data_id`。
|
||||
- 绑定记录更新为真实 `data_id`(但 node_id 保持不变)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 关键规则总结
|
||||
|
||||
- **node_id 是“同步系统内的稳定 ID”,必须持久化与复用。**
|
||||
- **data_id 是“业务系统的资源 ID”,由数据源加载或创建后回填。**
|
||||
- **加载顺序:先恢复持久化节点 → 再 load 数据源。**
|
||||
- **遇到已存在 data_id:复用 node_id;否则创建新节点。**
|
||||
- **CREATE 成功后只更新 data_id,不更换 node_id。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 相关文件参考
|
||||
|
||||
- 绑定与状态定义:见 [docs/状态定义规范.md](状态定义规范.md)
|
||||
- 编排流程:见 [docs/编排流程规范.md](编排流程规范.md)
|
||||
- BaseDataSource:见 [sync_system_new/datasource/datasource.py](../sync_system_new/datasource/datasource.py)
|
||||
- BaseApiHandler:见 [sync_system_new/datasource/api/handler.py](../sync_system_new/datasource/api/handler.py)
|
||||
|
||||
---
|
||||
|
||||
## 10. 明确规则与建议实现
|
||||
|
||||
- **DataSource.load_all 必须先按 `data_id` 命中已有节点并更新**,未命中时再由 Collection 创建新节点并分配新的 `node_id`。
|
||||
- **推荐实现方式**:先 `find_by_data_id`,命中走通用更新;未命中再创建新节点(无需强制 `upsert_by_data_id` 接口)。
|
||||
- **创建流程中的临时绑定/成功更新规则**:
|
||||
- CREATE 节点创建时:`binding_status = NORMAL`,`action = CREATE`,`status = PENDING`,`data_id = ""`。
|
||||
- 执行提交前置为 `status = IN_PROGRESS`(异步)或保持 `PENDING`(同步接口待执行)。
|
||||
- 成功回填后:`status = SUCCESS`,`data_id` 回填并写回主键字段,绑定记录保持 `node_id` 不变。
|
||||
- 过程中出现错误:`status = FAILED`,`error` 记录原因。
|
||||
- **异常节点持久化/恢复策略**:
|
||||
- 持久化时保留异常节点与错误信息。
|
||||
- 恢复时是否保留/清理异常节点应通过策略配置控制(默认建议保留以便人工修复)。
|
||||
@@ -0,0 +1,232 @@
|
||||
# Skip Sync 行为修复说明
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 1. **绑定失败的根本原因**
|
||||
|
||||
**问题现象**:
|
||||
- Company: 1/39 绑定
|
||||
- Supplier: 0/65202 绑定(完全没绑定!)
|
||||
- 导致依赖supplier的业务(contract, material等)也绑不上
|
||||
- 远程异常创建了74条数据
|
||||
|
||||
**根本原因有两个**:
|
||||
|
||||
#### 原因1:skip_sync 跳过了整个策略(包括 bind)
|
||||
|
||||
```python
|
||||
# 旧逻辑:skip_sync=True 时跳过整个策略
|
||||
if getattr(strategy, 'skip_sync', False):
|
||||
continue # ← 跳过了 bind/create/update 全部!
|
||||
```
|
||||
|
||||
修复后:
|
||||
```python
|
||||
# 新逻辑:bind() 始终执行,skip_sync 只跳过 create/update/sync
|
||||
await strategy.bind() # ← 始终执行
|
||||
|
||||
if getattr(strategy, 'skip_sync', False):
|
||||
continue # ← 只跳过 create/update
|
||||
```
|
||||
|
||||
#### 原因2:自动绑定ID解析失败没有设置DEPENDENCY_ERROR
|
||||
|
||||
```python
|
||||
# 旧逻辑:ID解析失败只是跳过
|
||||
if not resolved_key_dict:
|
||||
continue # ← 节点保持 MISSING,会被误创建!
|
||||
```
|
||||
|
||||
修复后:
|
||||
```python
|
||||
# 新逻辑:ID解析失败设置DEPENDENCY_ERROR
|
||||
if not resolved_key_dict:
|
||||
node.set_binding_status(BindingStatus.DEPENDENCY_ERROR, "业务键中的ID字段解析失败")
|
||||
continue # ← 节点为 DEPENDENCY_ERROR,不会被创建
|
||||
```
|
||||
|
||||
### 2. **状态与创建的关系**
|
||||
|
||||
| 状态 | 来源 | 允许创建 | 说明 |
|
||||
|------|------|:---:|------|
|
||||
| **UNCHECKED** | 加载后初始状态 | ❌ | bind() 未执行 |
|
||||
| **NORMAL** | 有绑定记录 | ❌ | 已绑定 |
|
||||
| **MISSING** | 无绑定记录 | ✅ | 真正的孤儿 |
|
||||
| **WARNING** | 业务键字段缺失 | ❌ | 数据不完整 |
|
||||
| **DEPENDENCY_ERROR** | 依赖不满足 | ❌ | 父节点未就绪 |
|
||||
| **ABNORMAL** | 数据损坏 | ❌ | 需人工处理 |
|
||||
|
||||
**关键原则**:
|
||||
- `create()` 只查找 `binding_status == MISSING` 的节点
|
||||
- 如果 bind() 没执行,状态是 UNCHECKED → 不会创建
|
||||
- 如果 bind() 执行了但依赖不满足 → DEPENDENCY_ERROR → 不会创建
|
||||
|
||||
### 3. **Supplier 默认行为变更**
|
||||
|
||||
**旧行为**:
|
||||
- `default_skip_sync = True` → 默认跳过同步
|
||||
- 需要在调用层设置 `force_sync_types=["supplier"]`
|
||||
|
||||
**新行为**:
|
||||
- `default_skip_sync` 已移除(使用基类默认值 False)
|
||||
- Supplier 默认会执行完整同步(bind/create/update)
|
||||
- 如需跳过,在调用层配置 `skip_sync_types=["supplier"]`
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 修改 1:分离 bind() 和 skip_sync
|
||||
|
||||
**新逻辑**:
|
||||
```python
|
||||
# sync_system_new/pipeline/full_sync_pipeline.py
|
||||
|
||||
# Step 1a: 绑定(始终执行)
|
||||
await strategy.bind()
|
||||
|
||||
# Step 1b: 检查是否跳过 create/update/sync
|
||||
if getattr(strategy, 'skip_sync', False):
|
||||
print(f"⏭️ Skipping create/update/sync for {node_type}")
|
||||
# 继续执行 pre_sync_check,但跳过 create/update/sync
|
||||
if hasattr(strategy, "pre_sync_check"):
|
||||
ok = await strategy.pre_sync_check()
|
||||
...
|
||||
continue
|
||||
|
||||
# Step 1c: 正常的 create/update
|
||||
await strategy.create()
|
||||
await strategy.update()
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- ✅ **bind() 始终执行**(建立绑定关系)
|
||||
- ✅ **skip_sync=True 只跳过 create/update/sync**(避免昂贵操作)
|
||||
- ✅ **pre_sync_check 仍然执行**(依赖检查)
|
||||
|
||||
### 修改 2:添加 force_sync_types 配置
|
||||
|
||||
**配置示例**:
|
||||
```python
|
||||
# tests/run_full_sync_pipeline_simple.py
|
||||
CONFIG = {
|
||||
# 第一次运行:从 API 加载 + 绑定 + 创建
|
||||
"force_sync_types": ["supplier"],
|
||||
"wipe_persistence_on_start": True,
|
||||
|
||||
# 第二次运行:从持久化加载 + 跳过同步
|
||||
# "handler_configs": {"supplier": {"load_mode": "persisted_only"}},
|
||||
# "skip_sync_types": ["supplier"],
|
||||
# "wipe_persistence_on_start": False,
|
||||
}
|
||||
```
|
||||
|
||||
**优先级**:
|
||||
1. **force_sync_types**(最高)→ `skip_sync = False`
|
||||
2. **skip_sync_types** → `skip_sync = True`
|
||||
3. **策略默认值** (default_skip_sync)
|
||||
|
||||
### 修改 3:添加测试日志保存
|
||||
|
||||
**功能**:
|
||||
```python
|
||||
# tests/run_full_sync_pipeline_simple.py
|
||||
log_path = log_dir / f"simple_pipeline_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
||||
sys.stdout = Tee(original_stdout, log_file)
|
||||
```
|
||||
|
||||
**输出位置**:
|
||||
```
|
||||
test_results/simple_pipeline_20260204_162345.log
|
||||
```
|
||||
|
||||
## 使用指南
|
||||
|
||||
### Phase 1: 首次运行(API + 绑定 + 创建)
|
||||
|
||||
```python
|
||||
CONFIG = {
|
||||
# 不需要特殊配置,所有类型默认都会同步
|
||||
"wipe_persistence_on_start": True, # 清空数据库
|
||||
}
|
||||
```
|
||||
|
||||
**预期结果**:
|
||||
- Supplier: 从API加载60000条 → 自动绑定(credit_code) → 拉取到本地 → 持久化
|
||||
- Company: 自动绑定 → 拉取
|
||||
- Contract等: 通过supplier_id/project_id绑定 → 创建
|
||||
|
||||
### Phase 2: 后续运行(持久化 + 跳过同步)
|
||||
|
||||
```python
|
||||
CONFIG = {
|
||||
"handler_configs": {
|
||||
"supplier": {"load_mode": "persisted_only"} # 从DB加载
|
||||
},
|
||||
"skip_sync_types": ["supplier"], # 跳过create/update(但仍执行bind)
|
||||
"wipe_persistence_on_start": False, # 保留数据
|
||||
}
|
||||
```
|
||||
|
||||
**预期结果**:
|
||||
- Supplier: 从DB加载(带绑定关系) → 执行bind(验证状态) → 跳过create/update
|
||||
- 其他业务: 正常同步
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 1. 删除远程异常创建的数据
|
||||
|
||||
```bash
|
||||
# TODO: 通过API删除远程的74条测试数据
|
||||
```
|
||||
|
||||
### 2. 清空数据库重新测试
|
||||
|
||||
```bash
|
||||
rm _runtime/test_simple.db
|
||||
python scripts/legacy/run_full_sync_pipeline_simple.py
|
||||
```
|
||||
|
||||
### 3. 验证绑定统计
|
||||
|
||||
**期望输出**:
|
||||
```
|
||||
Local Summary:
|
||||
company: 39/39 bindings ← 全部绑定
|
||||
supplier: 60000+/65202 bindings ← 大量绑定
|
||||
contract: XX/34 bindings ← 通过supplier_id绑定
|
||||
|
||||
Remote Summary:
|
||||
company: 39/39 bindings
|
||||
supplier: 60000+/60000 bindings
|
||||
contract: XX/155 bindings (XX creates)
|
||||
```
|
||||
|
||||
### 4. 检查日志文件
|
||||
|
||||
```bash
|
||||
cat test_results/simple_pipeline_*.log | grep "Skipping"
|
||||
```
|
||||
|
||||
**期望**:
|
||||
- 第一次运行:**不应该有** "Skipping" 输出
|
||||
- 第二次运行:`⏭️ Skipping create/update/sync for supplier`
|
||||
|
||||
## 风险评估
|
||||
|
||||
### 影响范围
|
||||
- ✅ 修复了 supplier/company 绑定失败问题
|
||||
- ✅ 防止未绑定节点异常创建
|
||||
- ✅ 保持了两阶段工作流(首次API+绑定,后续持久化)
|
||||
- ⚠️ 可能影响其他使用 skip_sync 的场景(需要测试)
|
||||
|
||||
### 向后兼容性
|
||||
- ✅ 原始脚本 (run_full_sync_pipeline_api.py) 不受影响
|
||||
- ✅ 没有 skip_sync 属性的策略行为不变
|
||||
- ✅ 新增的 force_sync_types 是可选参数
|
||||
|
||||
## 待办事项
|
||||
|
||||
- [ ] 测试所有业务类型的绑定统计
|
||||
- [ ] 验证依赖关系链(project → contract → material → detail)
|
||||
- [ ] 检查 construction_task 为什么没绑定(0/32)
|
||||
- [ ] 测试第二次运行的持久化加载逻辑
|
||||
- [ ] 更新文档说明 skip_sync 的新语义
|
||||
@@ -0,0 +1,72 @@
|
||||
# 业务流程与依赖关系
|
||||
|
||||
本文档描述推送系统涉及的业务实体及其依赖关系,用于指导同步顺序编排。
|
||||
|
||||
---
|
||||
|
||||
## 业务实体分类
|
||||
|
||||
### 1. 基础数据(仅拉取)
|
||||
|
||||
- **用户(User)**:拉取集团管理员、区域公司管理员及特定用户信息,用于跨平台穿透。其他用户需手动创建。
|
||||
- **公司(Company)**:仅拉取,不推送。
|
||||
- **供应商(Supplier)**:仅拉取,不推送。
|
||||
|
||||
### 2. 项目及扩展数据
|
||||
|
||||
**项目(Project)**
|
||||
- **绑定方式**:必须手动绑定(根节点)
|
||||
- **同步操作**:允许更新和拉取
|
||||
- **依赖项**:公司、附件(Attachment)
|
||||
|
||||
**项目扩展业务**
|
||||
- 通过 `(project_id, key)` 或 `(project_id, code)` 自动绑定
|
||||
- 允许创建、更新、拉取
|
||||
- 依赖项目
|
||||
|
||||
### 3. 合同及子业务
|
||||
|
||||
**合同(Contract)**
|
||||
- **绑定方式**:通过业务键自动绑定(需与 ECP 平台数据交叉检验)
|
||||
- **同步操作**:允许拉取、创建、更新、删除
|
||||
- **依赖项**:项目
|
||||
|
||||
**合同子业务**(施工任务、物资、结算、力能)
|
||||
- **绑定方式**:通过 `(contract_id, code)` 自动绑定
|
||||
- **同步操作**:允许拉取、创建、更新、删除
|
||||
- **特殊规则**:首次绑定后,项目侧不会同步创建远程已有的数据
|
||||
- **依赖项**:合同
|
||||
|
||||
**合同子业务明细**(施工明细、物资明细、结算明细、力能明细)
|
||||
- **绑定方式**:通过 `(parent_id, date)` 自动绑定
|
||||
- **同步操作**:允许拉取、创建、更新、删除
|
||||
- **特殊规则**:首次绑定后,项目侧不会同步创建远程已有的数据
|
||||
- **依赖项**:对应的合同子业务
|
||||
|
||||
---
|
||||
|
||||
## 依赖关系图
|
||||
|
||||
```
|
||||
Company (基础)
|
||||
↓
|
||||
Project (手动绑定)
|
||||
↓
|
||||
Contract (自动绑定)
|
||||
↓
|
||||
Contract Sub-Business (施工/物资/结算/力能)
|
||||
↓
|
||||
Details (明细)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 同步顺序原则
|
||||
|
||||
1. **依赖优先**:父节点必须先于子节点同步
|
||||
2. **绑定传递**:子节点的业务键构建依赖父节点的 ID 映射
|
||||
3. **故障隔离**:父节点同步失败时,子节点标记为 `DEPENDENCY_ERROR` 并跳过
|
||||
|
||||
详细状态定义参见:[sync_system_new/sync_system/STATE_DEFINITIONS.md](../sync_system_new/sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
详细架构设计参见:[sync_system_new/architecture_layers.md](../sync_system_new/architecture_layers.md)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
# 节点状态持久化与人工介入规范
|
||||
|
||||
> **代码实现**:`sync_system_new/common/state_reset.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. 持久化规则
|
||||
|
||||
### 1.1 持久化目标
|
||||
|
||||
| 目标 | 说明 |
|
||||
|------|------|
|
||||
| **可恢复性** | 系统重启后能从上次状态继续 |
|
||||
| **可观测性** | 失败和异常状态要保留,供人工查看 |
|
||||
| **可追溯性** | 失败信息持久化,不自动重试,需人工确认 |
|
||||
| **绑定稳定性** | 手工绑定一旦建立,永不自动改变 |
|
||||
|
||||
### 1.2 分阶段重置设计
|
||||
|
||||
状态重置分为两个阶段执行:
|
||||
|
||||
#### 阶段1:加载时重置(Collection.load_from_persistence)
|
||||
|
||||
| 字段 | 性质 | 持久化 | 阶段1重置 |
|
||||
|------|------|--------|-----------|
|
||||
| `node_id` | 恒定标识 | ✅ 必须 | ❌ 不重置 |
|
||||
| `data_id` | 业务主键 | ✅ 必须 | ❌ 不重置 |
|
||||
| `data` | 业务数据 | ✅ 必须 | ✅ **重置**(每次重新取数) |
|
||||
| `origin_data` | 原始快照 | ✅ 必须 | ✅ **重置**(每次重新取数) |
|
||||
| `depend_ids` | 依赖列表 | ❌ **不持久化** | ✅ **初始化为[]**(bind 阶段从 data 实时计算) |
|
||||
| `binding_status` | 绑定状态 | ✅ 必须 | ✅ **重置为 UNCHECKED** |
|
||||
| `action` | 同步意图 | ✅ 保存 | ❌ **保留**(用于阶段2判断) |
|
||||
| `status` | 执行状态 | ✅ 保存 | ❌ **保留**(全部保留,不重置) |
|
||||
| `error` | 错误信息 | ✅ 保存 | ✅ **重置为None**(清空上次错误) |
|
||||
| `context` | 扩展上下文 | ✅ 保存 | ❌ 不重置 |
|
||||
|
||||
#### 阶段2:数据加载后清理(Pipeline._cleanup_create_failed_zombies)
|
||||
|
||||
在数据加载完成后、策略执行前,执行CREATE失败节点清理:
|
||||
|
||||
1. **检查条件**:
|
||||
- 本地节点 `action == CREATE`(上次尝试创建)
|
||||
- 本地节点 `status == FAILED`(创建失败)
|
||||
|
||||
2. **清理动作**:
|
||||
- **删除本地失败节点**(从 collection 中移除)
|
||||
- 如果有绑定记录:
|
||||
- 解除绑定关系
|
||||
- 删除远程 collection 中的僵尸节点
|
||||
|
||||
3. **最后重置 action**:
|
||||
- 所有剩余节点的 `action` 重置为 NONE
|
||||
- 准备进入策略阶段
|
||||
|
||||
4. **下次同步的自动恢复**:
|
||||
- 被删除的节点会从数据源重新加载
|
||||
- 如果远程实际已创建成功(网络波动导致未获取到结果)→ 绑定阶段会自动绑定上
|
||||
- 如果远程实际也失败了 → 重新尝试创建
|
||||
|
||||
5. **UPDATE 阶段保护**:
|
||||
- UPDATE 操作会跳过所有 `status == FAILED` 的节点
|
||||
- 防止 UPDATE 阶段覆盖 CREATE/UPDATE 失败的状态和错误信息
|
||||
- 确保失败节点的 action 和 error 信息保持不变,直到下次同步清理
|
||||
|
||||
> **说明**:
|
||||
> - `data` / `origin_data`:每次运行从数据源重新获取,保证数据最新
|
||||
> - `depend_ids`:**不持久化**,每次 bind 阶段从 data 的业务字段(如 contract_id, project_id)实时提取
|
||||
> - `binding_status`:持久化用于审计,加载时重置为 `UNCHECKED`,由 bind() 重新判定
|
||||
> - `error`:**阶段1清空**,避免上次错误影响本次运行,新错误会在各阶段重新生成
|
||||
> - `action`:**阶段1保留**用于识别 CREATE 失败的节点,**阶段2清理后重置**
|
||||
> - `status`:**阶段1全部保留**(包括 FAILED、PRECONDITION_FAILED 等),不自动重置
|
||||
> - **CREATE 失败节点会被自动删除并重新加载**,UPDATE/DELETE 失败保留需人工处理
|
||||
> - **UPDATE 操作会跳过 FAILED 节点**,避免覆盖失败状态和错误信息
|
||||
|
||||
### 1.3 绑定记录 vs binding_status
|
||||
|
||||
| 概念 | 存储位置 | 持久性 | 如何改变 |
|
||||
|------|---------|--------|---------|
|
||||
| **绑定记录** | `bindings` 表 | **永久保留** | 只能手工 bind/unbind,或 CREATE 失败自动清理 |
|
||||
| **binding_status** | `nodes` 表 | 保存但可重判 | 每次 bind() 重新判定 |
|
||||
|
||||
### 1.4 CREATE 失败的自动恢复
|
||||
|
||||
当 CREATE 操作失败时,会产生"僵尸绑定":
|
||||
- 绑定记录已建立(local_id → remote_node_id)
|
||||
- 但远程节点的 `data_id` 为空(API 未返回真实 ID)
|
||||
|
||||
**下次同步时的自动恢复流程**:
|
||||
1. 阶段1加载:保留 `action=CREATE`
|
||||
2. 阶段2清理:检测到僵尸绑定,自动清理
|
||||
3. 本地节点恢复为 MISSING 状态
|
||||
4. 策略阶段重新判定,再次尝试 CREATE
|
||||
|
||||
---
|
||||
|
||||
## 2. 人工介入规范
|
||||
|
||||
### 2.1 介入时机
|
||||
|
||||
| 时机 | 场景 | 操作 |
|
||||
|------|------|------|
|
||||
| **运行前** | 查看上次失败记录 | 查看持久化的 error,决定是否修复后重试 |
|
||||
| **bind() 后** | 出现 ABNORMAL/WARNING | 检查数据一致性,手工修复或确认 |
|
||||
| **bind() 后** | 1:N / N:N 映射 | 手工绑定指定远程记录 |
|
||||
| **sync() 后** | 批量失败 | 分析失败原因,决定重试策略 |
|
||||
|
||||
### 2.2 binding_status 与介入需求
|
||||
|
||||
| binding_status | 含义 | 需要介入 | 说明 |
|
||||
|----------------|------|---------|------|
|
||||
| `UNCHECKED` | 未检查 | ❌ | 等待 bind() 判定 |
|
||||
| `NORMAL` | 绑定正常 | ❌ | 自动处理 |
|
||||
| `MISSING` | 无绑定记录 | ❌ | 自动创建 |
|
||||
| `WARNING` | 本地有绑定但远程无数据 | ⚠️ 可选 | 可能是远程删除,需确认 |
|
||||
| `ABNORMAL` | 状态不一致 | ✅ **必须** | 需人工排查 |
|
||||
| `DEPENDENCY_ERROR` | 依赖未就绪 | ❌ | 等依赖解决后自动重试 |
|
||||
|
||||
### 2.3 人工绑定操作
|
||||
|
||||
```python
|
||||
# 手工绑定(1:N 场景)
|
||||
binding_manager.bind(node_id="local_xxx", data_id="remote_xxx")
|
||||
|
||||
# 手工解绑
|
||||
binding_manager.unbind(node_id="local_xxx")
|
||||
```
|
||||
|
||||
绑定记录一旦建立,永不自动改变,只能手工操作。
|
||||
|
||||
### 2.4 职责分工
|
||||
|
||||
| 职责 | 系统自动 | 人工介入 |
|
||||
|------|---------|---------|
|
||||
| 1:1 自动绑定 | ✅ | - |
|
||||
| 1:N / N:N 绑定 | ❌ | ✅ |
|
||||
| NORMAL 节点同步 | ✅ | - |
|
||||
| MISSING 节点创建 | ✅ | - |
|
||||
| CREATE 失败重试 | ✅(自动清理僵尸) | ⚠️(需确认后手动重置) |
|
||||
| UPDATE 失败重试 | ❌(保留FAILED状态) | ✅(需确认后手动重置) |
|
||||
| ABNORMAL 处理 | ❌ | ✅ |
|
||||
| WARNING 确认 | ❌ | ✅(可选) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 总结
|
||||
|
||||
1. **分阶段重置**:
|
||||
- 阶段1(加载时):只重置 binding_status,**保留 action/status/error**
|
||||
- 阶段2(数据加载后):清理 CREATE 失败僵尸,然后重置 action
|
||||
2. **失败状态持久化**:FAILED 状态和 error 信息保留,不自动重试
|
||||
3. **绑定记录**:永久保留,除非 CREATE 失败自动清理或手工操作
|
||||
4. **人工介入**:失败需确认后手动重置,ABNORMAL/WARNING 需人工处理,1:N 绑定需手工指定
|
||||
@@ -0,0 +1,112 @@
|
||||
# 架构分层设计:四层模型
|
||||
|
||||
本架构旨在将同步系统的**数据容器**、**同步逻辑**、**执行层**与**编排流程**完全解耦,提供极简且类型安全的开发体验。
|
||||
|
||||
---
|
||||
|
||||
## 1. 架构概览
|
||||
|
||||
系统分为四层,依赖关系严格从上到下:
|
||||
|
||||
1. **通用层 (Common)**: 定义纯数据结构(Data Container)和基础工具。
|
||||
2. **同步系统层 (Sync System)**: 定义同步行为接口(SyncStrategy)与业务规则。
|
||||
3. **数据源层 (DataSource)**: 实现数据的加载与持久化,属于盲目执行层。
|
||||
4. **编排层 (Pipeline)**: 应用层逻辑,硬编码同步顺序,协调 ID 映射与错误传播。
|
||||
|
||||
---
|
||||
|
||||
## 2. 通用层 (Layer 0: Common)
|
||||
|
||||
本层不包含业务逻辑,仅定义数据契约。
|
||||
|
||||
- **SyncNode[T]**: 核心状态机容器。
|
||||
- `origin_data`: 原始数据(对应 `data_id`)。
|
||||
- `data`: 计算后的最新目标数据。
|
||||
- `data_id`: 业务主键ID。加载时必定有值,CREATE 节点初始为空字符串 `""`(布尔值为 False,可通过校验)。
|
||||
- `action`: 同步意图 (NONE, CREATE, UPDATE, DELETE)。
|
||||
- `status`: 执行状态 (PENDING, IN_PROGRESS, SUCCESS, FAILED, SKIPPED, PRECONDITION_FAILED)。
|
||||
- 详见 [状态定义规范 § 5.A](./状态定义规范.md#5-执行同步状态转换-physical-sync-state-transitions)
|
||||
- `binding_status`: 绑定状态 (UNCHECKED, NORMAL, MISSING, DEPENDENCY_ERROR, ABNORMAL, WARNING)。
|
||||
- 详见 [状态定义规范 § 1](./状态定义规范.md#1-核心状态判定表-core-binding-matrix)
|
||||
- `error`: 异常详情。
|
||||
- **DataCollection**: 节点的集合,提供类型安全的查询和过滤方法。
|
||||
- **BindingManager**:
|
||||
- **ID 映射**: 维护 `local_node_id` <-> `remote_node_id` 的双向映射。
|
||||
- **绑定键**: 使用 `node_id` 作为绑定记录的键,**一致不变**。CREATE 成功后只更新节点的 `data_id`,绑定记录不变。
|
||||
- **持久化**: 将映射关系持久化到存储(如 JSON/数据库)。
|
||||
- **Enums**: `SyncAction`, `SyncStatus`, `BindingStatus` 等。
|
||||
|
||||
---
|
||||
|
||||
## 3. 同步系统层 (Layer 1: Sync System)
|
||||
|
||||
核心业务逻辑层。通过实现 `SyncStrategy` 接口来定义特定实体的同步逻辑。
|
||||
|
||||
- **SyncStrategy[T] 接口**:
|
||||
- `bind()`:
|
||||
- 职责:判定 `binding_status` (NORMAL/MISSING/ABNORMAL/WARNING/DEPENDENCY_ERROR)
|
||||
- 详见 [状态定义规范 § 1-3](./状态定义规范.md)
|
||||
- `create()`:
|
||||
- 职责:处理孤儿节点(MISSING),在对方侧创建新节点并设置 `action=CREATE`
|
||||
- **ID 替换**: 创建新节点时,复制数据并将依赖字段的本地 ID 替换为远程 ID
|
||||
- **内联检查**: 通过 `IDResolver.resolve_and_validate()` 验证依赖 ID 解析
|
||||
- 详见 [状态定义规范 § 4.C](./状态定义规范.md)
|
||||
- `update()`:
|
||||
- 职责:处理差异节点(NORMAL 且有 diff),设置 `action=UPDATE`
|
||||
- **ID 替换**: 准备更新数据时,替换数据中的依赖 ID
|
||||
- **内联检查**: 验证目标节点 data_id 完整性,失败则设置 `PRECONDITION_FAILED`
|
||||
- **FAILED 保护**: 自动跳过 `status=FAILED` 的节点
|
||||
- 详见 [状态定义规范 § 4.A](./状态定义规范.md)
|
||||
---
|
||||
|
||||
## 4. 数据源层 (Layer 2: DataSource)
|
||||
|
||||
作为各个后端的适配器,负责数据加载与持久化。
|
||||
|
||||
- **职责**:
|
||||
- `load_nodes(node_type)`: 从后端加载并返回 `SyncNode` 集合,自动添加到 `DataCollection`。
|
||||
- `save_nodes(nodes)`:
|
||||
- 遍历节点,仅处理 `status == PENDING` 且 `action != NONE` 的节点。
|
||||
- 根据 `action` 执行相应的 CREATE/UPDATE/DELETE 操作。
|
||||
- 执行成功后,更新节点的 `status` 和相关信息(如新生成的 remote_id)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 编排层 (Layer 3: Pipeline)
|
||||
|
||||
最高层级,负责流程编排。
|
||||
|
||||
- **职责**:
|
||||
- **显式顺序**: 直接在代码中按顺序调用同步逻辑(例如:先同步项目,再同步合同)。
|
||||
- **故障传播**: 若前置实体某节点同步失败(`FAILED`),编排器在处理后续依赖节点时可将其标记为 `DEPENDENCY_ERROR`。
|
||||
- **生命周期管理**: 初始化 `BindingManager` 和 `DataCollection`,同步结束后调用持久化方法。
|
||||
|
||||
---
|
||||
|
||||
## 6. ID 映射与对齐:核心流程
|
||||
|
||||
为了解决本地数据引用本地 ID 与远程数据引用远程 ID 的冲突,系统采用以下映射逻辑:
|
||||
|
||||
### 绑定阶段 (Binding)
|
||||
- **时机**: `Strategy.bind`
|
||||
- **目标**: 在 `BindingManager` 中确定 local_id ↔ remote_id 映射
|
||||
- **手段**: 业务键匹配(如 Code 匹配)、历史记录恢复等
|
||||
|
||||
### 执行阶段 (Execution)
|
||||
- **时机**: `Strategy.create()` / `Strategy.update()` 阶段
|
||||
- **目标**: 在创建新节点或准备更新时,将依赖字段的本地 ID 替换为远程 ID
|
||||
- **手段**:
|
||||
- `create()`: 创建对方节点时,复制数据并替换所有依赖 ID
|
||||
- `update()`: 准备更新数据时,替换数据中的依赖 ID
|
||||
- **验证**: `_pre_commit_check` 在 create/update 最后检查,确保所有依赖节点都已有远程 ID
|
||||
|
||||
**注意**: ID 替换在 Strategy 的 create/update 阶段完成,DataSource 只负责盲目执行已准备好的数据。
|
||||
|
||||
---
|
||||
|
||||
## 7. 关键设计原则
|
||||
|
||||
- **删除类型依赖配置**: 依赖关系通过 `Pipeline` 中的代码调用顺序自然表达。
|
||||
- **无状态 DataSource**: 数据源不了解绑定逻辑,只看到 `action`、`status` 和 `binding_status`。
|
||||
- **BindingManager 为核心**: 负责 ID 空间映射和持久化。
|
||||
- **配置驱动**: 通过 `StrategyConfig` 和预设配置(ConfigPresets)灵活控制同步行为。
|
||||
@@ -0,0 +1,342 @@
|
||||
# 同步系统状态定义 (Final Spec)
|
||||
|
||||
本文档定义了同步系统的状态机逻辑。逻辑流转遵循以下顺序:
|
||||
1. **核心状态判定** (Core State)
|
||||
2. **依赖检查与ID解析** (Dependency)
|
||||
3. **自动绑定/发现** (Discovery)
|
||||
4. **策略执行** (Action)
|
||||
|
||||
---
|
||||
|
||||
## 0. 绑定状态枚举 (BindingStatus)
|
||||
|
||||
| 状态值 | 含义 | 来源 | 允许创建 |
|
||||
| :--- | :--- | :--- | :---: |
|
||||
| **UNCHECKED** | 未执行绑定检查 | 加载后的初始状态 | ❌ |
|
||||
| **NORMAL** | 绑定正常 | 核心状态判定 | ❌ |
|
||||
| **MISSING** | 无绑定记录(孤儿) | 核心状态判定 | ✅ |
|
||||
| **WARNING** | 业务键不完整 | 自动绑定阶段 | ❌ |
|
||||
| **ABNORMAL** | 数据损坏 | 核心状态判定 | ❌ |
|
||||
| **DEPENDENCY_ERROR** | 依赖未就绪 | 依赖检查或自动绑定 | ❌ |
|
||||
|
||||
**关键原则**:
|
||||
- **UNCHECKED 阻止创建**:加载后节点状态为 UNCHECKED,只有执行了 `bind()` 后才会转为其他状态
|
||||
- **只有 MISSING 状态才能触发 CREATE**:`create()` 方法只查找 `binding_status == MISSING` 的节点
|
||||
- **如果 bind() 被跳过**(如 skip_sync=True),节点保持 UNCHECKED,不会被创建
|
||||
|
||||
---
|
||||
|
||||
## 1. 核心状态判定表 (Core Binding Matrix)
|
||||
|
||||
**说明**:
|
||||
* **Binding Record Pair**: 数据库中的绑定记录 (必须成对出现,已排除单边绑定)。
|
||||
* **Data Valid**: 指数据是否可读、Schema校验是否通过。
|
||||
* **Warning vs Abnormal**:
|
||||
* `ABNORMAL`: 自身数据损坏。
|
||||
* `WARNING`: 自身健康,但因为对方损坏导致**连接不可用**。
|
||||
|
||||
| Bind Pair (Record) | Local Data (Valid?) | Remote Data (Valid?) | -> | **Local Status** | **Remote Status** | **说明** |
|
||||
| :---: | :---: | :---: | :--- | :--- | :--- | :--- |
|
||||
| **YES** | **YES** | **YES** | -> | **NORMAL** | **NORMAL** | **稳态**。链路完整,数据健康,可进行 Diff/Update。 |
|
||||
| **YES** | **YES** | **NO** | -> | **WARNING** | **ABNORMAL** | **远程损坏**。本地虽好,但链路已断 (Link Degraded)。禁止同步。 |
|
||||
| **YES** | **NO** | **YES** | -> | **ABNORMAL** | **WARNING** | **本地损坏**。远程虽好,但链路已断。禁止同步。 |
|
||||
| **YES** | **NO** | **NO** | -> | **ABNORMAL** | **ABNORMAL** | **双向损坏**。 |
|
||||
| **NO** | **YES** | N/A | -> | **MISSING** | N/A | **本地孤儿**。进入“依赖与发现”流程。 |
|
||||
| **NO** | N/A | **YES** | -> | N/A | **MISSING** | **远程孤儿**。进入“依赖与发现”流程。 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 依赖与业务键解析 (Dependency & ID Resolution)
|
||||
|
||||
**适用范围**: 所有涉及外键依赖 (Foreign Key) 的节点。
|
||||
**前置条件**: 核心状态 = `MISSING` (准备进行自动绑定或新建)。
|
||||
|
||||
在进行 `Auto-Bind` 或 `Create` 之前,必须先尝试构建**远程业务键**。
|
||||
例如:本地 `Contract(proj_id="P1", code="C01")` 想找远程对象,必须先查询 `P1` 对应的远程 ID `RP_99`,转换成 `(RP_99, "C01")` 才能去远程搜索。
|
||||
|
||||
| 依赖项 (Dependency) | 依赖项绑定状态 | -> | **能否构建业务键** | **节点状态** | **说明** |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **无依赖** | N/A | -> | ✅ Yes | **MISSING** | 根节点 (如 Project),直接进入下一阶段。 |
|
||||
| **有依赖** | **NORMAL** 且 `data_id` 非空(`status` 任意) | -> | ✅ Yes | **MISSING** | 依赖项已获得远程ID,可进入下一阶段。 |
|
||||
| **有依赖** | **NORMAL** 且 `data_id` 为空("",含 `status = FAILED`) | -> | ❌ No | **DEPENDENCY_ERROR** | 依赖项未回填ID,阻断绑定与同步。 |
|
||||
| **有依赖** | **MISSING / ABNORMAL** | -> | ❌ No | **DEPENDENCY_ERROR** | **依赖阻断**。父节点未同步或损坏,无法计算远程键,无法绑定,无法创建。 |
|
||||
| **有依赖** | **WARNING** | -> | ❌ No | **DEPENDENCY_ERROR** | 父节点状态不确定(如连接降级),禁止基于此建立新关系。 |
|
||||
|
||||
> **处理策略**: 处于 `DEPENDENCY_ERROR` 状态的节点,其动作强制为 **SKIP** (或 PENDING)。必须先修复父节点。
|
||||
>
|
||||
> **错误信息格式**: `DEPENDENCY_ERROR` 节点的 `error` 字段会包含详细的依赖失败信息:
|
||||
> - `dep_err: not_found: field_name(node_type)=value` - 依赖节点未找到
|
||||
> - `dep_err: field_name: status=FAILED` - 依赖节点状态为 FAILED
|
||||
> - 多个依赖失败时用分号分隔:`dep_err: not_found: project_id(project)=P1; contract_id: status=FAILED`
|
||||
|
||||
---
|
||||
|
||||
## 3. 自动绑定状态处理 (Auto-Binding State Handling)
|
||||
|
||||
此逻辑遵循“去噪后 1:1”原则:只有在排除掉所有健康同步对后,若剩余节点形成绝对的 1:1 关系,才允许自动绑定。
|
||||
|
||||
**配置说明与触发机制**:
|
||||
- **初始化场景**: 通常在系统第一次初始化或首次接入新实体时,配置 `auto_bind = True` 来对齐历史数据。
|
||||
- **后续同步**: 系统在日常同步中不建议开启全局自动绑定。自动绑定仅作为“发现”手段,一旦建立过关系的节点,其后续绑定操作通常仅在“自动创建”逻辑中伴随产生(详见第 4 节孤儿处理)。
|
||||
- **执行前提**: 只有当节点状态为 `MISSING` 且依赖解析成功(`DEPENDENCY_ERROR = False`)时,才会尝试以下探测逻辑。
|
||||
- **业务键完整性**: 若业务键字段缺失(如 `serial_number = null`),直接标记 `binding_status = WARNING`,并在 `node.error` 记录原因(`Auto-bind skipped: missing fields ...`),不参与自动绑定与孤儿创建判定。- **ID字段解析失败**: 若业务键包含ID字段(如 `supplier_id`)且依赖节点未绑定,ID解析失败,标记 `binding_status = DEPENDENCY_ERROR`,阻止孤儿创建。
|
||||
**核心算法**:
|
||||
1. **全集搜索**: 寻找本地/远端所有共享同一个业务键(Business Key)的记录。
|
||||
2. **排除稳态对**: 识别并移除**成对且互绑**的 `NORMAL` 记录。
|
||||
- 只有当本地 A 与远端 B 互为绑定对象,且状态皆为 `NORMAL` 时,才将这一对记录从待判定集合中剔除。
|
||||
- 若出现单边 `NORMAL` 记录(即其配对项不在本次搜索范围内或状态不属于另一端的 `NORMAL`),则不予剔除,视为环境污染项。
|
||||
3. **判定剩余**: 检查排除上述稳态对后的剩余集合(包含 `MISSING`, `ABNORMAL`, `WARNING` 及单边已占用的 `NORMAL` 记录)。
|
||||
|
||||
> **术语**:
|
||||
> - `L_remain` = 本地记录中,排除“成对稳态”后剩余的数量。
|
||||
> - `R_remain` = 远端记录中,排除“成对稳态”后剩余的数量。
|
||||
|
||||
| `L_remain` | `R_remain` | -> | **动作** | **说明** |
|
||||
| :---: | :---: | :--- | :--- | :--- |
|
||||
| **1** | **1** | -> | **BIND (Link)** | **1对1 自动对齐**:仅当两端剩余记录皆为 `MISSING` 且绝对 1:1 时,执行自动绑定。 |
|
||||
| **1** | **1** | -> | **SKIP** | **带障不处理**:若剩余记录中包含 `ABNORMAL` 等异常状态,说明存在历史冲突,不执行自动动作。 |
|
||||
| **N** | **0** | -> | **CREATE** | **可判定缺失**:业务键完整且唯一,本地存在而远端不存在(N:0)时,才允许进入孤儿创建策略。 |
|
||||
| 其他 | 其他 | -> | **SKIP** | **非 1:1 不处理**:存在多对多、多对一或无候选情况,系统保持原状。 |
|
||||
|
||||
**设计优势**:
|
||||
1. **对故障极端敏感**:环境中存在任何 `ABNORMAL` 记录都会阻断自动绑定,强制人工介入处理异常。
|
||||
2. **状态纯净**:失败时不产生任何中间态(如已废弃的 `AMBIGUOUS`),保持语义清晰。
|
||||
3. **静默自愈**: 当外界清理了环境且满足 1:1 条件后,系统下次同步会自动完成绑定。
|
||||
|
||||
### 3.1 空数据处理策略
|
||||
|
||||
**原则**:**空数据不推送**。
|
||||
|
||||
**空数据定义**:
|
||||
- 初始化时创建但未编辑的业务记录(如空合同、空施工任务)
|
||||
- 业务键字段为空或关键字段缺失的记录
|
||||
|
||||
**处理方式**:
|
||||
- 在自动绑定阶段,若业务键字段缺失,标记 `binding_status = WARNING`,记录原因
|
||||
- 不参与自动绑定与孤儿创建判定
|
||||
- 不推送到远程系统
|
||||
|
||||
**设计理由**:
|
||||
1. **远程系统简化**:远程只需处理完整数据,无需兼容空数据校验逻辑
|
||||
2. **避免垃圾数据**:空数据通常会被本地删除,若已推送则清理复杂
|
||||
3. **数据质量保障**:远程系统只能看到本地已正确编辑保存的业务
|
||||
|
||||
**配置方式**(Strategy 层):
|
||||
```python
|
||||
# 在 Strategy 配置中指定必填字段
|
||||
default_config = StrategyConfig(
|
||||
auto_bind_fields=["contract_id", "task_type"], # 业务键字段
|
||||
# 如果这些字段为空,节点将被标记为 WARNING 而非 MISSING
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 动作策略表 (Action Policy Matrix)
|
||||
|
||||
此表定义了在特定状态下,`execute` 阶段允许产生的 **意图行动 (`SyncAction`)**。
|
||||
|
||||
#### A. 稳态更新 (NORMAL)
|
||||
适用于已有绑定关系且链路健康的节点。
|
||||
|
||||
| 状态 | 动作条件 | 执行动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **NORMAL** | `compute_diff` 判定存在差异 | **UPDATE** |
|
||||
| **NORMAL** | `compute_diff` 判定无差异 | **NONE** |
|
||||
|
||||
#### B. 异常处理 (阻断态)
|
||||
处于这些状态的节点,引擎会自动中止后续的读写操作。
|
||||
|
||||
| 状态 | 说明 | 动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **DEPENDENCY_ERROR** | 父节点缺失/异常同步导致阻断 | **NONE** |
|
||||
| **ABNORMAL / WARNING** | 数据损坏或链路降级,需人工修复 | **NONE** |
|
||||
|
||||
#### C. 孤儿处理 (Create Only)
|
||||
适用于最终探测状态为 **MISSING** 且无法/不满足自动绑定的节点。
|
||||
|
||||
**本地孤儿 (Local Orphan)**: 本地有,远程无。
|
||||
| 策略配置 (`local_orphan_action`) | 对应的同步模式 | 动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **"create_remote"** | Push (本地推远端) | **CREATE** |
|
||||
| **"delete_local"** | Pull (远端拉本地) | **报错 (未实现)** |
|
||||
| **"none"** | Any | **NONE** |
|
||||
|
||||
**远程孤儿 (Remote Orphan)**: 远程有,本地无。
|
||||
| 策略配置 (`remote_orphan_action`) | 对应的同步模式 | 动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **"create_local"** | Pull (远端拉本地) | **CREATE** |
|
||||
| **"delete_remote"** | Push (本地推远端) | **报错 (未实现)** |
|
||||
| **"none"** | Any | **NONE** |
|
||||
|
||||
---
|
||||
|
||||
## 5. 执行同步状态转换 (Physical Sync State Transitions)
|
||||
|
||||
在策略执行完成、设置好 `action` 后,DataSource 层负责执行实际的同步操作并更新 `status` 字段。
|
||||
|
||||
### A. 执行状态枚举 (SyncStatus)
|
||||
|
||||
| 状态值 | 含义 | 适用场景 |
|
||||
| :--- | :--- | :--- |
|
||||
| **PENDING** | 待执行 | 初始状态、无动作的节点 |
|
||||
| **IN_PROGRESS** | 执行中 | 异步接口已提交,等待结果回调 |
|
||||
| **SUCCESS** | 执行成功 | 同步操作完成且成功 |
|
||||
| **FAILED** | 执行失败 | 同步操作失败,`error` 字段记录原因 |
|
||||
| **SKIPPED** | 已跳过 | 节点被主动跳过(如依赖未满足) |
|
||||
| **PRECONDITION_FAILED** | 前置条件失败 | create/update 内部验证发现问题 |
|
||||
|
||||
### B. 执行转换矩阵
|
||||
|
||||
#### 同步接口(一步式)
|
||||
|
||||
适用于同步 API(调用后立即返回成功/失败)。
|
||||
|
||||
| 输入: action | API 调用结果 | → | 输出: status | 副作用 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **CREATE** | 成功返回 (200/201) | → | **SUCCESS** | `data_id` 设置为远程返回的ID |
|
||||
| **CREATE** | 失败返回 (4xx/5xx) | → | **FAILED** | `error` 记录错误信息 |
|
||||
| **UPDATE** | 成功返回 (200) | → | **SUCCESS** | - |
|
||||
| **UPDATE** | 失败返回 (4xx/5xx) | → | **FAILED** | `error` 记录错误信息 |
|
||||
| **DELETE** | 成功返回 (200/204) | → | **SUCCESS** | 节点可能被移除 |
|
||||
| **DELETE** | 失败返回 (4xx/5xx) | → | **FAILED** | `error` 记录错误信息 |
|
||||
| **NONE** | - | → | **PENDING** | 不执行,保持原状 |
|
||||
|
||||
#### 异步接口(两步式)
|
||||
|
||||
适用于异步 API(提交后需要轮询或回调获取结果)。
|
||||
|
||||
| 输入: action | API 提交结果 | → | 输出: status | 后续操作 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **CREATE** | 提交成功 (202 Accepted) | → | **IN_PROGRESS** | 记录 task_id,等待轮询 |
|
||||
| **CREATE** | 提交失败 (4xx/5xx) | → | **FAILED** | `error` 记录错误 |
|
||||
| **IN_PROGRESS** | 轮询返回成功 | → | **SUCCESS** | `data_id` 设置为远程ID |
|
||||
| **IN_PROGRESS** | 轮询返回失败 | → | **FAILED** | `error` 记录错误 |
|
||||
| **IN_PROGRESS** | 超时未完成 | → | **FAILED** | `error` 记录 "Timeout" |
|
||||
|
||||
### B+. Handler 降级(action 取消)
|
||||
|
||||
> **代码实现**:各 `domain/*/api_handler.py` 中的 `update()` 方法。
|
||||
|
||||
当 Handler 在构建 API 请求数据时,发现实际无需更新的字段(如 schema 校验后所有字段与远程一致),
|
||||
Handler 会主动将节点的 `action` 从 `UPDATE` 降级为 `NONE`:
|
||||
|
||||
```
|
||||
action=UPDATE → Handler 校验 → 无实际变更字段 → action=NONE(不提交 API)
|
||||
```
|
||||
|
||||
此机制确保 DataSource 不会向远程发送无意义的空更新请求。
|
||||
|
||||
### C. 关键副作用
|
||||
|
||||
| 动作 | 成功时的副作用 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| **CREATE** | 临时绑定已建立 | 绑定关系可在提交前创建,用于推送与追踪;是否成功不影响该绑定存在 |
|
||||
| **CREATE** | 设置 `data_id` | 成功后从API响应中提取远程分配的ID,更新到节点 |
|
||||
| **CREATE** | 回写 `data` 主键 | DataSource 将远程返回的ID写回 `SyncNode.data`(如 `id`/`*_id` 字段) |
|
||||
| **CREATE** | 更新绑定记录 | 若使用临时ID,成功后替换为真实的远程ID |
|
||||
| **UPDATE** | 更新 `origin_data` | 将当前 `data` 保存为新的 `origin_data` |
|
||||
| **DELETE** | 移除绑定记录 | 删除成功后,清除对应的绑定关系 |
|
||||
|
||||
### D. 错误处理
|
||||
|
||||
| 错误类型 | 记录方式 | 重试策略 |
|
||||
| :--- | :--- | :--- |
|
||||
| **网络错误** | `error = "Network timeout"` | 可重试 |
|
||||
| **权限错误** | `error = "403 Forbidden"` | 不可重试,需人工介入 |
|
||||
| **数据校验错误** | `error = "Validation failed: ..."` | 不可重试,需修复数据 |
|
||||
| **依赖缺失** | `status = PRECONDITION_FAILED` | 不执行,等待依赖修复 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 同步检查规范 (Sync Check Specification)
|
||||
|
||||
在执行同步前后,需要进行状态检查以确保操作的合法性和完整性。
|
||||
|
||||
### A. 内联前置检查(create/update 阶段)
|
||||
|
||||
> **实现说明**:原 `_pre_commit_check` 方法已移除(保留空壳兼容接口)。
|
||||
> 所有有效检查已内联到 `_add_create_action()` 和 `_add_update_action()` 中。
|
||||
|
||||
**create() 阶段内联检查**:
|
||||
|
||||
| 检查类别 | 检查条件 | 不通过时 | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **数据完整性** | `src_node.get_data()` 不为空 | 跳过该节点,记录日志 | MISSING 但数据为空 |
|
||||
| **依赖 ID 解析** | `id_resolver.resolve_and_validate()` 成功 | `binding_status → DEPENDENCY_ERROR` | 依赖字段无法解析到目标系统 ID |
|
||||
|
||||
**update() 阶段内联检查**:
|
||||
|
||||
| 检查类别 | 检查条件 | 不通过时 | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **FAILED 保护** | `src_node.status != FAILED` | 跳过该节点 | 不覆盖上次失败的状态和错误 |
|
||||
| **数据完整性** | `src_node.get_data()` 不为空 | 跳过该节点 | NORMAL 但数据为空 |
|
||||
| **目标节点存在** | 通过绑定找到目标节点 | 跳过该节点 | 绑定记录指向的节点不在集合中 |
|
||||
| **data_id 完整性** | `target_node.data_id` 非空 | `status → PRECONDITION_FAILED` | UPDATE 必须有业务主键 |
|
||||
| **依赖 ID 解析** | `id_resolver.resolve_and_validate()` 成功 | `status → PRECONDITION_FAILED` | 依赖字段无法解析到目标系统 ID |
|
||||
| **差异检测** | `_needs_update()` 返回 True | 跳过该节点 | 无差异则不更新 |
|
||||
|
||||
> **注意**:以下检查项在当前实现中 **未覆盖**【未实现】:
|
||||
> - 状态合法性:`binding_status` 必须是已知状态
|
||||
> - 动作合法性:`CREATE/UPDATE` 只能用于 `NORMAL` 节点
|
||||
> - 绑定一致性:`NORMAL` 节点必须有绑定记录
|
||||
|
||||
### B. 同步后检查 (Post-Sync Check)
|
||||
|
||||
**目标**: 验证同步结果的完整性,发现残留问题。
|
||||
|
||||
> **实现说明**:当前 `_stage4_post_sync_check` 只打印摘要表格,不做异常检测。以下检查项均为【未实现】。
|
||||
|
||||
#### 检查项清单【未实现】
|
||||
|
||||
| 检查类别 | 检查条件 | 异常情况 | 严重程度 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **CREATE 完成性** | CREATE 节点应该有 `data_id` | `action = CREATE, status = SUCCESS` 但 `data_id = ""` | 🔴 ERROR |
|
||||
| **CREATE 绑定** | CREATE 节点应该有绑定记录 | CREATE 成功但无绑定 | 🔴 ERROR |
|
||||
| **UPDATE 完成性** | UPDATE 节点应该成功 | `action = UPDATE` 但 `status = FAILED` | ⚠️ WARNING |
|
||||
| **绑定保持** | UPDATE 节点的绑定应该保持 | UPDATE 后绑定记录丢失 | 🔴 ERROR |
|
||||
| **残留异常** | 不应有 ABNORMAL 节点 | 同步后仍有 `binding_status = ABNORMAL` | ⚠️ WARNING |
|
||||
| **残留依赖错误** | 不应有 DEPENDENCY_ERROR | 同步后仍有依赖阻断 | ⚠️ WARNING |
|
||||
|
||||
#### 统计指标
|
||||
|
||||
| 指标 | 计算方式 | 用途 |
|
||||
| :--- | :--- | :--- |
|
||||
| **成功率** | `SUCCESS / (CREATE + UPDATE)` | 评估同步质量 |
|
||||
| **异常率** | `(ABNORMAL + WARNING) / total` | 发现数据质量问题 |
|
||||
| **阻断率** | `DEPENDENCY_ERROR / total` | 发现依赖关系问题 |
|
||||
|
||||
#### 决策规则
|
||||
|
||||
| 检查结果 | ERROR 数量 | 决策 |
|
||||
| :--- | :--- | :--- |
|
||||
| ✅ 通过 | 0 | **继续持久化**,正常结束 |
|
||||
| ⚠️ 有警告 | 0, WARNING ≥1 | **继续持久化**,打印警告报告 |
|
||||
| ❌ 有错误 | ≥1 | **继续持久化**(已同步无法回滚),打印错误报告 |
|
||||
|
||||
> **注意**: Post-Sync Check 即使有 ERROR 也不会终止流程,因为同步已经执行,无法回滚。检查目的是发现问题并记录,供后续修复。
|
||||
|
||||
---
|
||||
|
||||
## 附录: 状态字段说明
|
||||
|
||||
### SyncNode 核心字段
|
||||
|
||||
| 字段 | 类型 | 设置阶段 | 含义 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `binding_status` | BindingStatus | Bind 阶段 | 绑定健康状态 |
|
||||
| `action` | SyncAction | Create/Update 阶段 | 待执行动作 |
|
||||
| `status` | SyncStatus | Physical Sync 阶段 | 执行结果状态 |
|
||||
| `data_id` | str | 数据加载 / CREATE 后 | 业务主键ID(CREATE 前为 "") |
|
||||
| `depend_ids` | List[str] | 数据加载 | 依赖节点的 node_id 列表 |
|
||||
| `error` | str \| None | Physical Sync 阶段 | 错误信息(失败时) |
|
||||
|
||||
### 状态流转时序
|
||||
|
||||
```
|
||||
[数据加载] [Bind] [Create/Update] [Physical Sync]
|
||||
binding_status: UNCHECKED → NORMAL/MISSING/... → (保持) → (保持)
|
||||
action: NONE → NONE → CREATE/UPDATE → (保持)
|
||||
status: PENDING → PENDING → PENDING → SUCCESS/FAILED
|
||||
data_id: 从源加载 → (保持) → 可能为 "" → CREATE 后设置
|
||||
```
|
||||
@@ -0,0 +1,498 @@
|
||||
# 状态机形式化规范
|
||||
|
||||
本文档用 **Guard-Event-Action (GEA)** 形式严格定义节点状态机。
|
||||
所有转换以代码实现为准,模糊之处在文档中显式标注。
|
||||
|
||||
> **代码基线**
|
||||
> - 枚举: `sync_system_new/common/types.py`
|
||||
> - 决策引擎: `sync_system_new/sync_system/decision.py`
|
||||
> - 重置策略: `sync_system_new/common/state_reset.py`
|
||||
> - 同步策略: `sync_system_new/sync_system/strategy.py`
|
||||
> - 物理同步: `sync_system_new/datasource/datasource.py`
|
||||
|
||||
> **配置基线(状态机真源)**
|
||||
> - `sync_system_new/state_machine/node_state_machine.yaml`
|
||||
|
||||
### 2026-02 对齐说明(重构前必读)
|
||||
|
||||
以下语义以 `node_state_machine.yaml` 为准,用于修正文档中易混淆点:
|
||||
|
||||
1. **E12a 为什么从 S01 出发?**
|
||||
- `S01` 只约束**源节点**是 NORMAL/NONE/PENDING 且有 `data_id`。
|
||||
- `E12a` 的 guard 是 `target_has_data_id=false`,检查对象是**目标节点**。
|
||||
- 所以“源节点在 S01”与“E12a 触发前置失败”并不冲突。
|
||||
|
||||
2. **S01 会不会触发创建?**
|
||||
- 当前配置中,create 的入口状态是 `S02(MISSING)`,不是 `S01`。
|
||||
- `S01` 进入的是 update_prepare(E12/E13/E14)。
|
||||
|
||||
3. **N:0 + create_enabled=true 的当前行为**
|
||||
- 自动绑定分支 `E08f`:`S02 -> S01`,并 `emit spawn_target_node_state: S06`。
|
||||
- create_prepare 分支 `E09b` 也可在检查成功后 `S02 -> S01 + spawn S06`。
|
||||
- 即:源节点不会停在“等待创建结果”的专用状态;创建执行结果体现在目标创建节点链路 `S06 -> S10/S11/S12/S13`。
|
||||
|
||||
4. **旧章节中的事件编号偏差**
|
||||
- 本文后续仍有部分“E11a/E11b/…”旧编号描述,已与当前 YAML 不一致。
|
||||
- 进行代码重构时,优先依据 YAML 的 `E08/E09/E10/E12/E13/E14/E15..E20`。
|
||||
|
||||
---
|
||||
|
||||
## §1 状态空间定义
|
||||
|
||||
### §1.1 状态维度
|
||||
|
||||
节点携带 **三个独立的状态字段** 和 **两个辅助字段**:
|
||||
|
||||
| 字段 | 枚举 | 值域 | 语义 |
|
||||
|------|------|------|------|
|
||||
| **B** – `binding_status` | `BindingStatus` | `UNCHECKED` · `NORMAL` · `MISSING` · `ABNORMAL` · `WARNING` · `DEPENDENCY_ERROR` | 绑定健康度 |
|
||||
| **A** – `action` | `SyncAction` | `NONE` · `CREATE` · `UPDATE` · `DELETE` | 待执行动作 |
|
||||
| **S** – `status` | `SyncStatus` | `PENDING` · `IN_PROGRESS` · `SUCCESS` · `FAILED` · `SKIPPED` · `PRECONDITION_FAILED` | 执行结果 |
|
||||
|
||||
辅助字段(影响 Guard 但不是状态维度):
|
||||
|
||||
| 字段 | 类型 | 语义 |
|
||||
|------|------|------|
|
||||
| `data_id` | `str` | 业务主键(空串 `""` = 尚未从远程获取) |
|
||||
| `error` | `str \| None` | 最近一次错误信息 |
|
||||
|
||||
理论组合 = 6 × 4 × 6 = **144**,实际可达 ≈ **23** 种。
|
||||
|
||||
### §1.2 可达状态枚举
|
||||
|
||||
以下列出所有在正常流程中可以到达的 `(binding_status, action, status)` 三元组。
|
||||
|
||||
| # | binding_status | action | status | 语义 | 产生阶段 |
|
||||
|---|---|---|---|------|---------|
|
||||
| R1 | UNCHECKED | NONE | PENDING | 首次加载 | 数据加载 |
|
||||
| R2 | UNCHECKED | NONE | SUCCESS | 从持久化恢复(上轮成功)后重置 | 阶段1/2重置 |
|
||||
| R3 | UNCHECKED | NONE | FAILED | 从持久化恢复(上轮失败)后重置 | 阶段1/2重置 |
|
||||
| R4 | UNCHECKED | NONE | SKIPPED | 从持久化恢复(上轮跳过)后重置 | 阶段1/2重置 |
|
||||
| R5 | UNCHECKED | NONE | PRECONDITION_FAILED | 从持久化恢复(上轮前置失败)后重置 | 阶段1/2重置 |
|
||||
| R6 | NORMAL | NONE | PENDING | 绑定正常,无需操作(首次) | bind.p1 |
|
||||
| R7 | NORMAL | NONE | SUCCESS | 绑定正常,无需操作(历史成功) | bind.p1 |
|
||||
| R8 | NORMAL | NONE | FAILED | 绑定正常但上次失败,被 FAILED 保护 | bind.p1 |
|
||||
| R9 | MISSING | NONE | PENDING | 孤儿,等待自动绑定或创建(首次) | bind.p1 |
|
||||
| R10 | MISSING | NONE | SUCCESS | 孤儿(历史成功但绑定丢失?) | bind.p1 |
|
||||
| R11 | ABNORMAL | NONE | * | 数据损坏,需人工 | bind.p1 |
|
||||
| R12 | WARNING | NONE | * | 多候选/对方损坏,需人工 | bind.p1/p3 |
|
||||
| R13 | DEPENDENCY_ERROR | NONE | PENDING | 依赖不满足 | bind.p2/p3/create |
|
||||
| R14 | NORMAL | CREATE | PENDING | 准备创建(目标节点) | create |
|
||||
| R15 | NORMAL | CREATE | IN_PROGRESS | 异步创建进行中 | sync |
|
||||
| R16 | NORMAL | CREATE | SUCCESS | 创建成功 | sync |
|
||||
| R17 | NORMAL | CREATE | FAILED | 创建失败 | sync |
|
||||
| R18 | NORMAL | UPDATE | PENDING | 准备更新(目标节点) | update |
|
||||
| R19 | NORMAL | UPDATE | IN_PROGRESS | 异步更新进行中 | sync |
|
||||
| R20 | NORMAL | UPDATE | SUCCESS | 更新成功 | sync |
|
||||
| R21 | NORMAL | UPDATE | FAILED | 更新失败 | sync |
|
||||
| R22 | NORMAL | UPDATE | PRECONDITION_FAILED | 更新前置条件失败 | update |
|
||||
| R23 | NORMAL | CREATE | SKIPPED | 创建被 Handler 跳过 | sync |
|
||||
|
||||
> **不可达组合(示例)**:
|
||||
> - `(MISSING, UPDATE, *)` — MISSING 节点不可能被安排 UPDATE
|
||||
> - `(ABNORMAL, CREATE, *)` — ABNORMAL 节点不可能被安排 CREATE
|
||||
> - `(*, DELETE, *)` — DELETE 尚未实现
|
||||
> - `(UNCHECKED, CREATE, *)` — UNCHECKED 是瞬态,在 bind 之前不会有 CREATE
|
||||
> - `(DEPENDENCY_ERROR, UPDATE, *)` — DEPENDENCY_ERROR 节点不可能进入 update 流程
|
||||
|
||||
### §1.3 辅助字段约束
|
||||
|
||||
| 对应状态 | binding_status | action | status | data_id 约束 | error 约束 |
|
||||
|---------|---|---|---|-------------|-----------|
|
||||
| R14 | NORMAL | CREATE | PENDING | `""` (待远程返回) | None |
|
||||
| R16 | NORMAL | CREATE | SUCCESS | 非空 (远程回填) | None |
|
||||
| R17 | NORMAL | CREATE | FAILED | `""` (未回填) | 非空 |
|
||||
| R22 | NORMAL | UPDATE | PRECONDITION_FAILED | * | 非空 |
|
||||
| R13 | DEPENDENCY_ERROR | NONE | PENDING | * | 非空 |
|
||||
|
||||
---
|
||||
|
||||
## §2 不变量 (Invariants)
|
||||
|
||||
以下约束在**任何事件执行后**都必须成立。违反即为 Bug。
|
||||
|
||||
```
|
||||
INV-1 B = UNCHECKED ⟹ A = NONE
|
||||
(UNCHECKED 是瞬态,在 bind 之前不允许有动作)
|
||||
|
||||
INV-2 B ∈ {ABNORMAL, WARNING, DEPENDENCY_ERROR} ⟹ A = NONE
|
||||
(阻断态节点不允许执行任何同步动作)
|
||||
|
||||
INV-3 B = MISSING ⟹ A ∈ {NONE, CREATE}
|
||||
(MISSING 节点只能等待创建或保持不动)
|
||||
|
||||
INV-4 A = CREATE ⟹ B = NORMAL
|
||||
(CREATE 动作只出现在目标节点上,其 binding_status 已被设为 NORMAL)
|
||||
|
||||
INV-5 A = UPDATE ⟹ B = NORMAL
|
||||
(UPDATE 动作只对 NORMAL 节点执行)
|
||||
|
||||
INV-6 S = IN_PROGRESS ⟹ A ∈ {CREATE, UPDATE, DELETE}
|
||||
(只有提交过 API 的节点才可能处于 IN_PROGRESS)
|
||||
|
||||
INV-7 S = PRECONDITION_FAILED ⟹ A = UPDATE
|
||||
(PRECONDITION_FAILED 只在 update 阶段产生)
|
||||
|
||||
INV-8 A = CREATE ∧ S = SUCCESS ⟹ data_id ≠ ""
|
||||
(创建成功必须回填 data_id)
|
||||
|
||||
INV-9 S = FAILED ⟹ error ≠ None
|
||||
(失败必须有错误信息)
|
||||
|
||||
INV-10 B = DEPENDENCY_ERROR ⟹ error ≠ None
|
||||
(依赖阻断必须有错误信息)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §3 事件与转换
|
||||
|
||||
### §3.1 事件总览图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 节点生命周期事件流 │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
|
||||
持久化恢复 策略层 (Strategy) 执行层 (DataSource)
|
||||
═══════════ ══════════════════════════════════ ══════════════════════════
|
||||
┌──────────────────────────────┐
|
||||
┌──────┐ │ bind() │ ┌──────────────────────┐
|
||||
│E01 │──────────▶│ E04 ─┐ │ │ sync_all() │
|
||||
│RESET1│ │ E05 ├─ phase1: core_state │ │ │
|
||||
└──┬───┘ │ E06 ─┘ │ │ E12 SYNC_OK │
|
||||
│ │ E07 ── phase2: dep_check │ ┌───▶│ E13 SYNC_FAIL │
|
||||
┌──▼───┐ │ E08 ─┐ │ │ │ E14 SYNC_ASYNC │
|
||||
│E02 │ │ E09 ├─ phase3: auto_bind │ │ │ E15 SYNC_TIMEOUT │
|
||||
│ZOMBIE│ │ E10 ─┘ │ │ │ E16 HANDLER_SKIP │
|
||||
└──┬───┘ └──────────────────────────────┘ │ │ E17 HANDLER_DOWN │
|
||||
│ ┌──────────────────────────────┐ │ └──────────────────────┘
|
||||
┌──▼───┐ │ create() / update() │ │
|
||||
│E03 │──────────▶│ E11a CREATE_OK │────┘
|
||||
│RESET2│ │ E11b CREATE_DEP_FAIL │
|
||||
└──────┘ │ E11c UPDATE_DIFF │
|
||||
│ E11d UPDATE_PRECOND_FAIL │
|
||||
│ E11e UPDATE_SKIP_FAILED │
|
||||
└──────────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
### §3.2 状态转换详解
|
||||
|
||||
本节按 Pipeline 执行阶段组织。每个阶段包含:
|
||||
1. **状态转换图**:状态(R 编号)为节点,事件(E 编号)为有向边
|
||||
2. **转换表**:每个事件的精确规格——起始状态、判断条件、结束状态、副作用
|
||||
|
||||
---
|
||||
|
||||
#### 🔄 阶段 0:重置
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
╔═══════════════════════════════════════╗
|
||||
║ 任意持久化终态 (R6 ~ R23) ║
|
||||
╚═══════════════════╤═══════════════════╝
|
||||
│ E01
|
||||
▼
|
||||
┌────────────────────────────────────────┐ E02
|
||||
│ 瞬态: UNCHECKED │────────────▶ [节点删除 + 解除绑定]
|
||||
│ (action 保留, status 保留, error=None) │
|
||||
└────────────────────┬──────────────────┘
|
||||
│ E03 (存活节点)
|
||||
▼
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ [R1] UNCHECKED, NONE, PENDING ← 首次加载 ║
|
||||
║ [R2] UNCHECKED, NONE, SUCCESS ← 上轮成功 ║
|
||||
║ [R3] UNCHECKED, NONE, FAILED ← 上轮失败 ║
|
||||
║ [R4] UNCHECKED, NONE, SKIPPED ← 上轮跳过 ║
|
||||
║ [R5] UNCHECKED, NONE, PRECONDITION_FAILED ← 上轮前置 ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E01**: PHASE1_RESET | R6~R23 (任意持久化终态) | 节点从持久化加载 | 瞬态 (UNCHECKED, action 保留, status 保留) | error → None; data/origin_data → None |
|
||||
| **E02**: ZOMBIE_KILL | 瞬态 | action = CREATE ∧ (status = FAILED ∨ data_id = "") | **节点删除** | 解除绑定关系; 对 local/remote 两侧都扫描 |
|
||||
| **E03**: ACTION_RESET | 瞬态 (存活节点) | E02 完成后所有存活节点 | R1 / R2 / R3 / R4 / R5 (按原 status 分) | action → NONE |
|
||||
|
||||
> **代码**: `NodeStateReset.get_phase1_reset_defaults()` · `cleanup_create_failed_zombies()` · `reset_action_for_nodes()`
|
||||
|
||||
---
|
||||
|
||||
#### 🔗 阶段 1:Bind
|
||||
|
||||
Bind 由三个子阶段串行执行。后一阶段只处理前一阶段的遗留 MISSING 节点。
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
[R1~R5] UNCHECKED, NONE, *
|
||||
│
|
||||
│ ══════════ Phase 1: 核心状态判定 ══════════
|
||||
│
|
||||
├── E04 (有绑定, 双方数据 VALID) ───────────▶ [R6/R7/R8] NORMAL ──────▶ 出口 ✅
|
||||
├── E04 (有绑定, 自身数据缺失/损坏) ────────▶ [R11] ABNORMAL ─────────▶ 出口 🔒
|
||||
├── E04 (有绑定, 对方数据缺失/损坏) ────────▶ [R12] WARNING ──────────▶ 出口 🔒
|
||||
│
|
||||
└── E05 (无绑定记录) ───────────────────────▶ [R9] MISSING
|
||||
│
|
||||
══════════ Phase 2: 依赖检查 ══════════ │
|
||||
│
|
||||
├── E06 (data = None) ──────────────────────▶ [R11] ABNORMAL ──────▶ 出口 🔒
|
||||
├── E07 (依赖节点不满足) ───────────────────▶ [R13] DEP_ERROR ─────▶ 出口 🔒
|
||||
│ (无依赖配置 或 依赖全部满足 → 继续 ▼)
|
||||
│
|
||||
══════════ Phase 3: 自动绑定 ══════════
|
||||
│
|
||||
├── E08 (auto_bind 关闭) ──────────────────▶ [R12] WARNING ────────▶ 出口 🔒
|
||||
├── E09 (去噪后 1:1 匹配成功) ─────────────▶ [R6] NORMAL ─────────▶ 出口 ✅
|
||||
├── E10a (去噪后非 1:1, 多候选) ───────────▶ [R12] WARNING ────────▶ 出口 🔒
|
||||
├── E10b (业务键字段缺失) ─────────────────▶ [R12] WARNING ────────▶ 出口 🔒
|
||||
├── E10c (业务键中 ID 字段解析失败) ───────▶ [R13] DEP_ERROR ─────▶ 出口 🔒
|
||||
│
|
||||
└── (1:0 无远程匹配)
|
||||
├── create_enabled = True → [R9] MISSING ──────────────▶ 进入 create
|
||||
└── create_enabled = False → [R12] WARNING ─────────────▶ 出口 🔒
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E04**: BIND_PAIRED | R1~R5 | 有绑定记录 ∧ 双方数据 VALID | R6 (PENDING) / R7 (SUCCESS) / R8 (FAILED) — status 保持 | 远程节点同步设置 binding_status |
|
||||
| **E04**: BIND_PAIRED (自身异常) | R1~R5 | 有绑定记录 ∧ 本方数据缺失或损坏 | R11 (ABNORMAL) | 对方节点设为 WARNING |
|
||||
| **E04**: BIND_PAIRED (对方异常) | R1~R5 | 有绑定记录 ∧ 对方数据缺失或损坏 | R12 (WARNING) | 对方节点设为 ABNORMAL |
|
||||
| **E05**: BIND_ORPHAN | R1~R5 | 无绑定记录 | R9 (MISSING, NONE, status 保持) | — |
|
||||
| **E06**: DATA_NULL | R9 | binding_status = MISSING ∧ data = None | R11 (ABNORMAL) | error = "数据损坏: 节点数据为空或不存在" |
|
||||
| **E07**: DEP_CHECK_FAIL | R9 | depend_fields 配置非空 ∧ ∃依赖节点: 不存在 ∨ status ≠ NORMAL ∨ data_id 为空 | R13 (DEPENDENCY_ERROR) | error = "依赖项不满足: ..."; depend_ids 填充 |
|
||||
| **E08**: AUTOBIND_DISABLED | R9 | auto_bind = False 或 auto_bind_fields 为空 | R12 (WARNING) | — |
|
||||
| **E09**: AUTOBIND_OK | R9 | 去噪后 local:remote = 1:1 ∧ 双方都是 MISSING | R6 (NORMAL) | 建立绑定记录; 双方都设为 NORMAL |
|
||||
| **E10a**: AUTOBIND_AMBIGUOUS | R9 | 去噪后非 1:1 (多候选) | R12 (WARNING) | error += "存在多个候选节点" |
|
||||
| **E10b**: AUTOBIND_KEY_MISSING | R9 | auto_bind_fields 中有字段不存在于 data | R12 (WARNING) | error += "缺少业务键字段: ..." |
|
||||
| **E10c**: AUTOBIND_ID_FAIL | R9 | 业务键包含 ID 字段 ∧ ID 解析失败 | R13 (DEPENDENCY_ERROR) | error = "业务键中的ID字段解析失败: ..." |
|
||||
| **E10d**: ORPHAN_CREATE_DISABLED | R9 | 去噪后 1:0 ∧ create_enabled = False | R12 (WARNING) | error += "孤儿且不允许自动创建" |
|
||||
|
||||
> **E04 核心状态矩阵** (完整查表):
|
||||
>
|
||||
> | | 远程: VALID | 远程: ABSENT | 远程: INVALID |
|
||||
> |---|---|---|---|
|
||||
> | **本地: VALID** | 本:NORMAL 远:NORMAL | 本:WARNING 远:ABNORMAL | 本:WARNING 远:ABNORMAL |
|
||||
> | **本地: ABSENT** | 本:ABNORMAL 远:WARNING | 本:ABNORMAL 远:ABNORMAL | — |
|
||||
> | **本地: INVALID** | 本:ABNORMAL 远:WARNING | — | 本:ABNORMAL 远:ABNORMAL |
|
||||
>
|
||||
> 不在矩阵中的组合 → 默认 (ABNORMAL, ABNORMAL)
|
||||
|
||||
> **代码**: `SyncDecisionEngine.determine_core_status()` · `_phase_core_state()` · `_check_dependencies_for_nodes()` · `_phase_auto_binding()`
|
||||
|
||||
---
|
||||
|
||||
#### ⚡ 阶段 2:Create / Update
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
═══════════════ Create ═══════════════
|
||||
|
||||
[R9] MISSING, NONE, PENDING (源节点, data ≠ None)
|
||||
│
|
||||
├── E11a (ID 解析成功) ────▶ 源节点: [R9] → [R6] NORMAL
|
||||
│ 新建目标节点: → [R14] NORMAL, CREATE, PENDING
|
||||
│ + 建立绑定记录, 目标 data_id = ""
|
||||
│
|
||||
└── E11b (ID 解析失败) ────▶ 源节点: [R9] → [R13] DEPENDENCY_ERROR
|
||||
|
||||
|
||||
═══════════════ Update ═══════════════
|
||||
|
||||
[R6/R7] NORMAL, NONE, PENDING/SUCCESS (源节点, status ≠ FAILED)
|
||||
│
|
||||
├── E11c (差异检测通过) ────▶ 目标节点 → [R18] NORMAL, UPDATE, PENDING
|
||||
├── E11d.1 (目标 data_id="") ▶ 目标节点 → [R22] status = PRECONDITION_FAILED
|
||||
├── E11d.2 (ID 解析失败) ───▶ 目标节点 → [R22] action = UPDATE, status = PRECOND_FAIL
|
||||
└── (无差异) ──────────────▶ 保持不变
|
||||
|
||||
|
||||
═══════════════ FAILED 保护 ═══════════════
|
||||
|
||||
[R8] NORMAL, NONE, FAILED (源节点)
|
||||
│
|
||||
└── E11e ──────────────────▶ 跳过,保持 [R8] 不变
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 (源节点) | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E11a**: CREATE_OK | R9 (MISSING) | data ≠ None ∧ IDResolver.resolve_and_validate() = OK | 源 → R6 (NORMAL); **新建**目标 → R14 | 建立绑定; 新节点 data = 已替换 ID 的副本, data_id = "" |
|
||||
| **E11b**: CREATE_DEP_FAIL | R9 (MISSING) | data ≠ None ∧ IDResolver.resolve_and_validate() = FAIL | R13 (DEPENDENCY_ERROR) | error = "创建时依赖 ID 未解析: ..." |
|
||||
| **E11c**: UPDATE_DIFF | R6/R7 (NORMAL, status≠FAILED) | 目标存在 ∧ 目标 data_id ≠ "" ∧ ID 解析 OK ∧ _needs_update() = True | 目标 → R18 (UPDATE, PENDING) | 目标: data 替换, error = None |
|
||||
| **E11d**: UPDATE_PRECOND_FAIL | R6/R7 (NORMAL, status≠FAILED) | 目标 data_id = "" (d1) 或 ID 解析失败 (d2) | 目标 → R22 (UPDATE, PRECONDITION_FAILED) | error = "目标缺少 data_id" 或 "依赖 ID 未解析" |
|
||||
| **E11e**: UPDATE_SKIP_FAILED | R8 (NORMAL, FAILED) | status = FAILED | R8 不变 | 保护上次的 error 和 FAILED 状态,不做任何修改 |
|
||||
|
||||
> **代码**: `_add_create_action()` · `_add_update_action()`
|
||||
|
||||
---
|
||||
|
||||
#### 📡 阶段 3:Sync(物理同步)
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
[R14] NORMAL, CREATE, PENDING [R18] NORMAL, UPDATE, PENDING
|
||||
│ │
|
||||
└───────────────┬───────────────────┘
|
||||
│
|
||||
├── E12 (API 成功) ──────▶ [R16] CREATE,SUCCESS / [R20] UPDATE,SUCCESS
|
||||
├── E13 (API 失败) ──────▶ [R17] CREATE,FAILED / [R21] UPDATE,FAILED
|
||||
├── E16 (Handler 跳过) ──▶ [R23] CREATE, SKIPPED
|
||||
├── E17 (Handler 降级) ──▶ [R6] NORMAL, NONE, PENDING (仅 UPDATE)
|
||||
│
|
||||
└── E14 (异步提交) ──────▶ [R15] CREATE,IN_PROGRESS / [R19] UPDATE,INP
|
||||
│
|
||||
├── (轮询成功) ──▶ [R16] / [R20] SUCCESS
|
||||
└── E15 (超时) ──▶ [R17] / [R21] FAILED
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E12**: SYNC_OK | R14 或 R18 | Handler API 返回 SUCCESS | R16 (CREATE) 或 R20 (UPDATE) | error → None; data_id 回填 (CREATE); origin_data 更新 (UPDATE) |
|
||||
| **E13**: SYNC_FAIL | R14 或 R18 | Handler API 返回 FAILED | R17 (CREATE) 或 R21 (UPDATE) | error = Handler 返回的错误信息 |
|
||||
| **E14**: SYNC_ASYNC | R14 或 R18 | Handler API 返回 IN_PROGRESS | R15 (CREATE) 或 R19 (UPDATE) | 记录 task_id, 进入轮询队列 |
|
||||
| **E15**: SYNC_TIMEOUT | R15 或 R19 | 轮询次数 > max_retries | R17 (CREATE) 或 R21 (UPDATE) | error = "Async task timeout after N seconds" |
|
||||
| **E16**: HANDLER_SKIP | R14 或 R18 | Handler API 返回 SKIPPED | R23 (CREATE,SKIPPED) | error → None |
|
||||
| **E17**: HANDLER_DOWNGRADE | R18 (仅 UPDATE) | Handler 运行时发现无实际变更字段 | R6 (NORMAL, NONE, PENDING) | action: UPDATE → NONE; 不提交 API; 统计列从 update 移入 none |
|
||||
|
||||
> **代码**: `BaseDataSource._handle_task_result()` · `_poll_async_tasks()` · `domain/*/api_handler.py`
|
||||
|
||||
---
|
||||
|
||||
## §4 终态分类与死胡同
|
||||
|
||||
### §4.1 终态分类
|
||||
|
||||
| 分类 | 状态 | (binding_status, action, status) | 语义 | 下一轮行为 |
|
||||
|------|------|------|------|---------|
|
||||
| ✅ 成功 | R16 | (NORMAL, CREATE, SUCCESS) | 创建成功 | →R2→bind→R7→update 检查 |
|
||||
| ✅ 成功 | R20 | (NORMAL, UPDATE, SUCCESS) | 更新成功 | →R2→bind→R7→update 检查 |
|
||||
| ❌ 失败 | R17 | (NORMAL, CREATE, FAILED) | 创建失败 | E02 zombie 判定→删除节点→对方回到 R9 重建 |
|
||||
| ❌ 失败 | R21 | (NORMAL, UPDATE, FAILED) | 更新失败 | →R3→bind→R8→FAILED 保护(E11e)→保持 |
|
||||
| 🔒 阻断 | R11 | (ABNORMAL, NONE, \*) | 数据损坏 | 每轮重新 bind 检查; 需人工修复数据 |
|
||||
| 🔒 阻断 | R12 | (WARNING, NONE, \*) | 多候选/对方异常 | 每轮重新 bind 检查; 需人工绑定或修复 |
|
||||
| 🔒 阻断 | R13 | (DEPENDENCY_ERROR, NONE, PENDING) | 依赖不满足 | 每轮重新检查依赖; 依赖修复后自动恢复 |
|
||||
| ⏭ 跳过 | R23 | (NORMAL, CREATE, SKIPPED) | Handler 跳过创建 | →R4→bind→R6→update 检查(无绑定则再 create) |
|
||||
| 🔄 异步 | R15 | (NORMAL, CREATE, IN\_PROGRESS) | 创建异步中 | 轮询直到 SUCCESS 或超时→FAILED |
|
||||
| 🔄 异步 | R19 | (NORMAL, UPDATE, IN\_PROGRESS) | 更新异步中 | 轮询直到 SUCCESS 或超时→FAILED |
|
||||
| 🔄 前置失败 | R22 | (NORMAL, UPDATE, PRECONDITION\_FAILED) | 前置条件不满足 | →R5→bind→R6/R7→update 重试 |
|
||||
|
||||
### §4.2 恢复路径
|
||||
|
||||
```
|
||||
R17 (CREATE, FAILED):
|
||||
持久化 → 下轮 E01 → 瞬态(UNCHECKED, CREATE, FAILED)
|
||||
→ E02: action=CREATE ∧ (status=FAILED ∨ data_id="") → 满足 zombie 条件
|
||||
→ 删除节点 + 解除绑定
|
||||
→ 对方节点回到 R9 (MISSING) → 重新进入 create 流程
|
||||
|
||||
R21 (UPDATE, FAILED):
|
||||
持久化 → 下轮 E01 → 瞬态(UNCHECKED, UPDATE, FAILED)
|
||||
→ E02: action=UPDATE ≠ CREATE → 非 zombie,存活
|
||||
→ E03: action → NONE → R3 (UNCHECKED, NONE, FAILED)
|
||||
→ bind → R8 (NORMAL, NONE, FAILED)
|
||||
→ E11e: FAILED 保护 → 跳过 update → 保持 R8
|
||||
⚠ 需人工清除 FAILED 才能恢复
|
||||
|
||||
R22 (UPDATE, PRECONDITION_FAILED):
|
||||
持久化 → 下轮 E01 → 瞬态(UNCHECKED, UPDATE, PRECONDITION_FAILED)
|
||||
→ E02: action=UPDATE ≠ CREATE → 非 zombie,存活
|
||||
→ E03: action → NONE → R5 (UNCHECKED, NONE, PRECONDITION_FAILED)
|
||||
→ bind → R6/R7 (NORMAL) → update 流程重试
|
||||
|
||||
R11 (ABNORMAL):
|
||||
每轮 E01 重置 → bind 重新检查
|
||||
→ 若数据被人工修复 → E04 → R6/R7/R8 (NORMAL)
|
||||
→ 若数据仍损坏 → 再次 R11
|
||||
|
||||
R12 (WARNING):
|
||||
每轮 E01 重置 → bind 重新检查
|
||||
→ 若人工建立了绑定 → E04 → R6/R7 (NORMAL)
|
||||
→ 若对方数据被修复 → E04 → R6/R7 (NORMAL)
|
||||
|
||||
R13 (DEPENDENCY_ERROR):
|
||||
每轮 E01 重置 → bind 重新检查依赖
|
||||
→ 依赖节点达到 NORMAL 且 data_id 非空后
|
||||
→ E07 通过 → 继续 auto_bind 或 create 流程
|
||||
```
|
||||
|
||||
### §4.3 FAILED 保护机制详解
|
||||
|
||||
FAILED 保护确保失败节点不会被后续流程静默覆盖,保留 error 信息供人工调查。
|
||||
|
||||
```
|
||||
进入条件:
|
||||
节点经过 bind 后为 R8 (NORMAL, NONE, FAILED)
|
||||
即: 绑定关系正常,但上一轮执行失败
|
||||
|
||||
保护行为:
|
||||
strategy._add_update_action() 中:
|
||||
if source.status == SyncStatus.FAILED:
|
||||
skip (→ 事件 E11e)
|
||||
结果: R8 原样保持 → 持久化 → 下一轮依然 R8
|
||||
|
||||
解除条件 (需人工介入):
|
||||
1. 清除 error 字段 (→ None)
|
||||
2. 将 status 改为 PENDING 或 SUCCESS
|
||||
3. 下轮 bind 后 → R6 或 R7 → 正常进入 update 流程
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §5 完备性分析
|
||||
|
||||
### §5.1 状态 × 事件矩阵
|
||||
|
||||
行 = 当前状态,列 = 可能触发的事件。`→Rx` = 转换到目标状态,`—` = 不可能触发。
|
||||
|
||||
| 状态 | E01 | E02 | E03 | E04/E05 | E06~E10 | E11a/b | E11c/d/e | E12~E17 |
|
||||
|------|-----|-----|-----|---------|---------|--------|----------|---------|
|
||||
| R1~R5 | — | — | — | →R6~R13 | — | — | — | — |
|
||||
| R6/R7 | →瞬态 | — | — | — | — | — | →R18/R22 | — |
|
||||
| R8 | →瞬态 | — | — | — | — | — | →R8(skip) | — |
|
||||
| R9 | →瞬态 | — | — | — | →R6/R11~R13 | →R6+R14/R13 | — | — |
|
||||
| R11~R13 | →瞬态 | — | — | — | — | — | — | — |
|
||||
| R14 | →瞬态 | — | — | — | — | — | — | →R15~R17/R23 |
|
||||
| R15 | →瞬态 | — | — | — | — | — | — | →R16/R17 |
|
||||
| R18 | →瞬态 | — | — | — | — | — | — | →R6/R19~R21/R23 |
|
||||
| R19 | →瞬态 | — | — | — | — | — | — | →R20/R21 |
|
||||
| R16/R17 | →瞬态 | — | — | — | — | — | — | — |
|
||||
| R20~R23 | →瞬态 | — | — | — | — | — | — | — |
|
||||
|
||||
> **读表方式**: 找到当前状态行和事件列组的交叉点,即可得到目标状态。`—` 表示该状态不可能触发该事件。
|
||||
|
||||
### §5.2 已知 GAP
|
||||
|
||||
| GAP | 描述 | 风险 | 建议 |
|
||||
|-----|------|------|------|
|
||||
| GAP-1 | `set_binding_status()` / `set_action()` / `set_status()` 是纯 setter,不验证转换合法性 | 中 | 加入前置断言:检查 (当前状态, 新状态) 是否匹配某条已知转换 |
|
||||
| GAP-2 | INV-1 ~ INV-10 未在代码中 assert | 中 | 每次 setter 调用后或阶段结束时断言所有不变量 |
|
||||
| GAP-3 | R22 (PRECONDITION\_FAILED) 节点下一轮行为路径需验证 | 低 | 已补充恢复路径: R22→E01→E03→R5→bind→R6/R7→update 重试 |
|
||||
| GAP-4 | Handler 降级 (E17) 后 status 残留为 PENDING 但 action 已清零 | 低 | 可考虑降级时同时重置 status 为 SUCCESS(当前保持 PENDING) |
|
||||
| GAP-5 | 物理同步后缺少整体一致性检查 (post-sync invariant check) | 低 | 在 `sync_all()` 结束后遍历所有节点验证 INV-1 ~ INV-10 |
|
||||
|
||||
---
|
||||
|
||||
## §6 引用
|
||||
|
||||
| 文档 | 路径 |
|
||||
|------|------|
|
||||
| 枚举定义 | `sync_system_new/common/types.py` |
|
||||
| 决策引擎 | `sync_system_new/sync_system/decision.py` |
|
||||
| 重置策略 | `sync_system_new/common/state_reset.py` |
|
||||
| 同步策略 | `sync_system_new/sync_system/strategy.py` |
|
||||
| 物理同步 | `sync_system_new/datasource/datasource.py` |
|
||||
| ID 解析 | `sync_system_new/sync_system/resolve_ids.py` |
|
||||
| 节点生命周期(叙事) | [节点生命周期状态转移](./节点生命周期状态转移.md) |
|
||||
@@ -0,0 +1,534 @@
|
||||
# 同步编排流程规范 (Pipeline Specification)
|
||||
|
||||
本文档定义了完整的同步编排流程,包括各阶段的职责、节点状态转换和检查点。
|
||||
|
||||
> **详细的状态定义和转换规则,请参考**: [STATE_DEFINITIONS.md](../sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
---
|
||||
|
||||
## 流程概览
|
||||
|
||||
同步系统的完整执行流程分为 5 个阶段:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 0: 初始化 (Initialization) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - 创建 Collection (Local/Remote) │
|
||||
│ - 创建 BindingManager │
|
||||
│ - 注册 SyncStrategy (各业务类型) │
|
||||
│ - 创建 DataSource (Local/Remote) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 1: 数据加载 (Data Loading) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 节点状态: binding_status=UNCHECKED, action=NONE, status=PENDING │
|
||||
│ - Persistence.load_nodes() → 从持久化恢复 │
|
||||
│ - DataSource.load_all() → 从数据源加载 │
|
||||
│ - BindingManager.load_bindings() → 加载绑定关系 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 2 & 3: 策略执行与同步 (按 node_type 顺序) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ For each node_type in sync_order: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 2.1 bind() → 绑定判定 │ │
|
||||
│ │ 2.2 create() → 设置 CREATE action │ │
|
||||
│ │ └─ 内联 ID 解析 + 前置检查 │ │
|
||||
│ │ 2.3 Commit Creates → 立即同步 CREATE 节点 │ │
|
||||
│ │ └─ DataSource.sync_all(poll_async=True) │ │
|
||||
│ │ 2.4 update() → 设置 UPDATE action │ │
|
||||
│ │ └─ 内联 ID 解析 + 前置检查 │ │
|
||||
│ │ 2.5 Commit Updates → 立即同步 UPDATE 节点 │ │
|
||||
│ │ └─ DataSource.sync_all(poll_async=True) │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 说明: │
|
||||
│ - 每个 node_type 完整同步后才处理下一个(保证依赖顺序) │
|
||||
│ - commit 操作内部包含异步轮询,无需独立轮询阶段 │
|
||||
│ - sync_all() 自动过滤 action=CREATE/UPDATE 的节点 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 4: 同步结果报告 (Summary Report) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - 打印同步结果摘要 │
|
||||
│ * 节点统计(按 action/status 分类) │
|
||||
│ * 绑定关系统计 │
|
||||
│ * 异常节点检查(data_id 缺失、绑定缺失等) │
|
||||
│ - 收集统计信息(成功/失败/残留问题) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 5: 状态持久化 (State Persistence) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - Collection.persist() → 保存节点状态 │
|
||||
│ - BindingManager.persist() → 保存绑定关系 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
【流程完成】
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 各阶段节点状态
|
||||
|
||||
### Stage 0: 初始化
|
||||
|
||||
**输出**: 所有组件实例化完成。
|
||||
|
||||
---
|
||||
|
||||
### Stage 1: 数据加载
|
||||
|
||||
**节点状态**:
|
||||
```python
|
||||
binding_status = BindingStatus.UNCHECKED # 未判定
|
||||
action = SyncAction.NONE # 无动作
|
||||
status = SyncStatus.PENDING # 待处理
|
||||
data_id = <从数据源加载> # 已有业务ID
|
||||
origin_data = <从数据源加载> # 原始数据快照
|
||||
data = <从数据源加载> # 当前数据
|
||||
depend_ids = <从数据源加载> # 依赖节点列表
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- `data_id` 在加载时**必定有值**(来自数据源)
|
||||
- 只有待创建的新节点 `data_id` 才可能为 ""(空字符串)
|
||||
- 从持久化恢复时应重置所有 `action` 为 `NONE`
|
||||
- `binding_status` 初始值是 `UNCHECKED`,不是 `None`
|
||||
|
||||
---
|
||||
|
||||
### Stage 2.1: Bind (状态判定)
|
||||
|
||||
**状态转换**: `binding_status: UNCHECKED → NORMAL/MISSING/ABNORMAL/WARNING/DEPENDENCY_ERROR`
|
||||
|
||||
**可能的结果状态**:
|
||||
|
||||
| 结果状态 | 含义 | 占比 |
|
||||
|---------|------|-----|
|
||||
| **NORMAL** | 有绑定,数据健康 | 大部分 |
|
||||
| **MISSING** | 无绑定,孤儿节点 | 少量 |
|
||||
| **ABNORMAL** | 有绑定,自身数据损坏 | 极少 |
|
||||
| **WARNING** | 有绑定,对方数据损坏 | 极少 |
|
||||
| **DEPENDENCY_ERROR** | 依赖未满足 | 少量 |
|
||||
|
||||
**详细规则**: 参考 [STATE_DEFINITIONS.md § 1-3](../sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
**补充约束**:
|
||||
- 若依赖节点 `binding_status = NORMAL` 但 `data_id` 为空(含 `status = FAILED`),视为依赖阻断。
|
||||
- 只要依赖节点已回填 `data_id`,即使其 `status = FAILED`,后续类型仍允许进入 Create/Update。
|
||||
- 自动绑定只在**业务键完整且唯一**时才尝试:
|
||||
- 若业务键字段缺失(如 `serial_number = null`),设置 `binding_status = WARNING`,并在 `node.error` 记录原因:`Auto-bind skipped: missing fields ...`。
|
||||
- 若同一业务键出现多对多/多对一,设置 `binding_status = WARNING`,并在 `node.error` 记录原因:`Auto-bind skipped: ambiguous candidates`。
|
||||
- 以上情况仅记录 **Warning**,不进行自动绑定。
|
||||
|
||||
---
|
||||
|
||||
### Stage 2.2: Create (孤儿处理)
|
||||
|
||||
**状态转换**: `action: NONE → CREATE` (对 MISSING 节点)
|
||||
|
||||
**补充约束**:
|
||||
- `binding_status = WARNING` 的节点不会进入 CREATE(`create()` 只查找 MISSING 节点)
|
||||
- 创建时会通过 `IDResolver.resolve_and_validate()` 二次验证依赖 ID,失败则设置 `DEPENDENCY_ERROR`
|
||||
|
||||
**副作用**:
|
||||
- 在对方 Collection 创建新节点
|
||||
- 新节点的 `binding_status = NORMAL, action = CREATE, data_id = ""`
|
||||
- 建立绑定记录
|
||||
- 原 MISSING 节点也变为 `NORMAL`
|
||||
|
||||
**示例**:
|
||||
```
|
||||
Before:
|
||||
local_node: binding_status=MISSING, action=NONE
|
||||
|
||||
After Create:
|
||||
local_node: binding_status=NORMAL, action=NONE
|
||||
remote_node (新建): binding_status=NORMAL, action=CREATE, data_id=""
|
||||
绑定记录: local_id ↔ remote_temp_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Stage 2.3: Update (差异同步)
|
||||
|
||||
**状态转换**: `action: NONE → UPDATE` (对 NORMAL 且有差异的节点)
|
||||
|
||||
**前提条件**:
|
||||
- `binding_status = NORMAL`
|
||||
- `status != FAILED`(保护上次失败的状态和错误信息)
|
||||
- `compute_diff()` 判定有差异
|
||||
- 配置的 `update_direction` 决定哪一方节点设置 UPDATE
|
||||
|
||||
**内联检查**:
|
||||
- 目标节点 `data_id` 为空 → `status = PRECONDITION_FAILED`
|
||||
- `IDResolver.resolve_and_validate()` 失败 → `status = PRECONDITION_FAILED`
|
||||
- Handler 校验后无实际变更字段 → `action` 降级为 `NONE`(不提交)
|
||||
|
||||
---
|
||||
|
||||
### Stage 2 & 3: 策略执行与同步
|
||||
|
||||
**执行顺序**: 按 `sync_order` 顺序逐个处理 node_type
|
||||
|
||||
**单个 node_type 的完整流程**:
|
||||
|
||||
```
|
||||
For node_type in sync_order:
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.1 Bind - 绑定判定 │
|
||||
│ - 设置 binding_status: NORMAL/MISSING/... │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.2 Create - 创建策略 │
|
||||
│ - 处理 MISSING 节点,设置 action=CREATE │
|
||||
│ - 内联 ID 解析验证 (resolve_and_validate) │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.3 Commit Creates - 立即同步 CREATE │
|
||||
│ - DataSource.sync_all(poll_async=True) │
|
||||
│ - 自动过滤 action=CREATE 的节点 │
|
||||
│ - 内部包含异步轮询(IN_PROGRESS→SUCCESS)│
|
||||
│ - ⭐ 执行 data_id 回填和绑定更新 │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.4 Update - 更新策略 │
|
||||
│ - 处理差异节点,设置 action=UPDATE │
|
||||
│ - 内联 ID 解析验证 + data_id 检查 │
|
||||
│ - FAILED 节点自动跳过 │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.5 Commit Updates - 立即同步 UPDATE │
|
||||
│ - DataSource.sync_all(poll_async=True) │
|
||||
│ - 自动过滤 action=UPDATE 的节点 │
|
||||
│ - 内部包含异步轮询(IN_PROGRESS→SUCCESS)│
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
下一个 node_type
|
||||
```
|
||||
|
||||
**关键特性**:
|
||||
1. **按类型顺序**: 每个 node_type 完全同步后才处理下一个(保证依赖顺序)
|
||||
2. **立即提交**: create/update 后立即同步,不等待所有策略执行完
|
||||
3. **内置轮询**: `sync_all(poll_async=True)` 内部自动轮询异步任务
|
||||
4. **data_id 回填**: CREATE 成功后立即回填 data_id,下游依赖可用
|
||||
|
||||
**同步状态转换**:
|
||||
|
||||
**同步接口(一步式)**:
|
||||
```
|
||||
action=CREATE, API 成功 → status=SUCCESS, data_id=<远程ID>
|
||||
action=CREATE, API 失败 → status=FAILED, error=<错误信息>
|
||||
action=UPDATE, API 成功 → status=SUCCESS
|
||||
action=UPDATE, API 失败 → status=FAILED, error=<错误信息>
|
||||
action=NONE → status=PENDING (不执行)
|
||||
```
|
||||
|
||||
**异步接口(两步式,内置轮询)**:
|
||||
```
|
||||
action=CREATE, 提交成功 → status=IN_PROGRESS, task_id=<任务ID>
|
||||
status=IN_PROGRESS, 轮询中... → status=IN_PROGRESS (保持)
|
||||
status=IN_PROGRESS, 轮询成功 → status=SUCCESS, data_id=<远程ID>
|
||||
status=IN_PROGRESS, 轮询失败 → status=FAILED, error=<错误信息>
|
||||
status=IN_PROGRESS, 超时 → status=FAILED, error="Timeout"
|
||||
```
|
||||
|
||||
**关键副作用**(由 DataSource 在 sync_all 中执行):
|
||||
- CREATE 成功: `data_id` 从 "" 更新为远程分配的 ID,并回写 `data` 主键字段
|
||||
- CREATE 成功: 绑定记录从临时ID更新为真实ID
|
||||
- UPDATE 成功: `origin_data` 更新为当前 `data`
|
||||
- DELETE 成功: 移除绑定记录
|
||||
|
||||
**skip_sync 处理**:
|
||||
- 如果 `strategy.skip_sync = True`,跳过 create/update/commit 步骤
|
||||
- bind 步骤始终执行(用于状态判定)
|
||||
|
||||
**详细规则**: 参考 [STATE_DEFINITIONS.md § 5](../sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
---
|
||||
|
||||
### Stage 4: 同步结果报告
|
||||
|
||||
**目标**: 打印同步结果摘要,帮助用户了解同步情况
|
||||
|
||||
**报告内容**:
|
||||
1. **节点统计**:按 node_type 统计各种 action/status 的节点数量
|
||||
2. **绑定关系**:每个 node_type 的绑定记录数
|
||||
3. **异常检查**:扫描并报告异常情况:
|
||||
- CREATE 成功但 data_id 为空(DataSource 回填失败)
|
||||
- CREATE 成功但绑定记录缺失
|
||||
- UPDATE/CREATE 失败的节点及错误原因
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
================================================================================
|
||||
📊 Local Collection Summary
|
||||
================================================================================
|
||||
Node Type Bindings Create Update Delete None Total
|
||||
--------------------------------------------------------------------------------
|
||||
project 5/5 0(0/0/0) 2(2/0/0) 0(0/0/0) 3 5(5/0/0)
|
||||
contract 10/12 2(2/0/0) 5(5/0/0) 0(0/0/0) 5 12(12/0/0)
|
||||
```
|
||||
|
||||
**注意**: 此阶段不修改任何状态,仅作为信息展示。
|
||||
|
||||
---
|
||||
|
||||
### Stage 5: 状态持久化
|
||||
|
||||
**持久化内容**:
|
||||
- `binding_status`, `action`, `status` 的最终值
|
||||
- `data_id` (可能在 CREATE 后更新)
|
||||
- `error` (如果失败)
|
||||
- 绑定关系的完整映射
|
||||
|
||||
---
|
||||
|
||||
## 错误处理策略
|
||||
|
||||
| 阶段 | 失败类型 | 处理策略 |
|
||||
|------|---------|---------|
|
||||
| Stage 0 | 初始化失败 | **终止流程**,抛出异常 |
|
||||
| Stage 1 | 数据加载失败 | **终止流程**,抛出异常 |
|
||||
| Stage 2 & 3 | 代码异常 | **终止流程**,抛出异常 |
|
||||
| Stage 2: create/update 内联检查 | 依赖ID未解析、data_id缺失 | **继续流程**,节点标记为 DEPENDENCY_ERROR 或 PRECONDITION_FAILED |
|
||||
| Stage 2 & 3 | API 调用失败 | **继续流程**,标记节点 FAILED |
|
||||
| Stage 4 | - | 总是继续,仅作为报告 |
|
||||
| Stage 5 | 持久化失败 | **记录错误**,不影响内存状态 |
|
||||
|
||||
---
|
||||
|
||||
## 节点状态完整时间线
|
||||
|
||||
```
|
||||
┌──────────────┬─────────────┬────────┬────────┬─────────┐
|
||||
│ 阶段 │ binding_ │ action │ status │ data_id │
|
||||
│ │ status │ │ │ │
|
||||
├──────────────┼─────────────┼────────┼────────┼─────────┤
|
||||
│ 数据加载 │ UNCHECKED │ NONE │PENDING │ 已加载 │
|
||||
│ Bind │ NORMAL/... │ NONE │PENDING │ 已加载 │
|
||||
│ Create │ NORMAL │ CREATE │PENDING │ ""* │
|
||||
│ Commit Create│ NORMAL │ CREATE │SUCCESS │ 远程ID** │
|
||||
│ Update │ NORMAL │ UPDATE │PENDING │ 已加载 │
|
||||
│ Commit Update│ NORMAL │ UPDATE │SUCCESS │ 已加载 │
|
||||
└──────────────┴─────────────┴────────┴────────┴─────────┘
|
||||
|
||||
* 新创建的节点 data_id 初始为 ""
|
||||
** CREATE 成功后 data_id 立即更新为远程分配的ID,下游依赖可用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置驱动的流程控制
|
||||
|
||||
### 跳过某些阶段
|
||||
|
||||
```python
|
||||
pipeline_config = {
|
||||
"skip_bind": False, # 是否跳过 bind
|
||||
"skip_create": False, # 是否跳过 create
|
||||
"skip_update": False, # 是否跳过 update
|
||||
"skip_post_check": False, # 是否跳过同步后检查
|
||||
"fail_on_warning": False, # Pre-Check 时是否将 WARNING 视为失败
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**:`skip_pre_check` 已移除,原 `_pre_commit_check` 逻辑已内联到 create/update 方法中。
|
||||
```
|
||||
|
||||
### 策略预设应用
|
||||
|
||||
```python
|
||||
# 首次同步:启用自动绑定,双向创建
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("first_sync")
|
||||
|
||||
# 日常同步:仅推送更新
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("push_only")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 幂等性保证
|
||||
|
||||
**要求**: 同一个 Collection 的多次同步应该是幂等的。
|
||||
|
||||
**设计保证**:
|
||||
1. **Bind 阶段**: 基于绑定记录判定,已绑定节点不会重复绑定
|
||||
2. **Create 阶段**: 已有绑定的节点 (NORMAL) 不会重复创建
|
||||
3. **Update 阶段**: 基于 `compute_diff()` 判定,无差异则不执行
|
||||
4. **Sync 阶段**: `action=NONE` 的节点跳过执行
|
||||
|
||||
**前提条件**:
|
||||
- 绑定记录正确持久化
|
||||
- 节点的 `binding_status` 正确保存和加载
|
||||
- `compute_diff()` 逻辑准确
|
||||
|
||||
---
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 关键指标
|
||||
|
||||
| 指标 | 含义 | 阶段 |
|
||||
|------|------|-----|
|
||||
| `nodes_loaded` | 加载的节点总数 | Stage 1 |
|
||||
| `nodes_normal` | NORMAL 状态节点数 | Stage 2.1 |
|
||||
| `nodes_missing` | MISSING 状态节点数 | Stage 2.1 |
|
||||
| `nodes_abnormal` | ABNORMAL+WARNING 节点数 | Stage 2.1 |
|
||||
| `nodes_dep_error` | DEPENDENCY_ERROR 节点数 | Stage 2.1 |
|
||||
| `actions_create` | CREATE 动作节点数 | Stage 2.2 |
|
||||
| `actions_update` | UPDATE 动作节点数 | Stage 2.3 |
|
||||
| `sync_success` | 同步成功节点数 | Stage 3 |
|
||||
| `sync_failed` | 同步失败节点数 | Stage 3 |
|
||||
| `success_rate` | 成功率 (success/total) | Stage 4 |
|
||||
|
||||
### 日志级别
|
||||
|
||||
```
|
||||
INFO: 流程阶段切换、统计信息
|
||||
DEBUG: 节点级别的详细操作
|
||||
WARN: 检查发现的警告、同步失败
|
||||
ERROR: 检查发现的错误、致命异常
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [STATE_DEFINITIONS.md](../sync_system/STATE_DEFINITIONS.md) - 详细的状态定义和转换规则
|
||||
- [CHECK_SPEC.md](./CHECK_SPEC.md) - 检查点的实现细节和代码示例(可选)
|
||||
# 1. 持久化 Collection
|
||||
await local_collection.persist()
|
||||
await remote_collection.persist()
|
||||
|
||||
# 2. 持久化 Binding
|
||||
await binding_manager.persist()
|
||||
```
|
||||
|
||||
**持久化内容**:
|
||||
- 节点的 `binding_status`, `action`, `status`, `error`
|
||||
- 节点的 `data_id`(可能在 CREATE 后更新)
|
||||
- 绑定关系的完整映射
|
||||
|
||||
---
|
||||
|
||||
## 错误处理策略
|
||||
|
||||
### 各阶段的失败处理
|
||||
|
||||
| 阶段 | 失败原因示例 | 处理策略 |
|
||||
|------|------------|---------|
|
||||
| Stage 1: 数据加载 | 网络错误、文件缺失 | **终止流程**,抛出异常 |
|
||||
| Stage 2.1: Bind | 代码bug | **终止流程**,抛出异常 |
|
||||
| Stage 2.2-2.3: Create/Update | 代码bug | **终止流程**,抛出异常 |
|
||||
| Stage 2: create/update 内联检查 | 依赖ID未解析、data_id缺失 | **继续流程**,节点标记为 DEPENDENCY_ERROR 或 PRECONDITION_FAILED |
|
||||
| Stage 3: Physical Sync | API错误、权限不足 | **继续流程**,标记节点为 FAILED |
|
||||
| Stage 4: Post-Sync Check | 部分节点同步失败 | **继续流程**,打印警告 |
|
||||
| Stage 5: Persistence | 磁盘满、权限错误 | **记录错误**,但不影响内存状态 |
|
||||
|
||||
### 部分成功的处理
|
||||
|
||||
在 Stage 3 中,允许部分节点成功、部分失败:
|
||||
- 成功的节点: `status = SUCCESS`
|
||||
- 失败的节点: `status = FAILED`, `error = "错误信息"`
|
||||
|
||||
Post-Sync Check 会统计成功率并给出警告。
|
||||
|
||||
---
|
||||
|
||||
## 配置驱动的流程控制
|
||||
|
||||
### 跳过某些阶段
|
||||
|
||||
通过配置控制哪些阶段执行:
|
||||
|
||||
```python
|
||||
pipeline_config = {
|
||||
"skip_bind": False, # 是否跳过 bind
|
||||
"skip_create": False, # 是否跳过 create
|
||||
"skip_update": False, # 是否跳过 update
|
||||
"skip_post_check": False, # 是否跳过同步后检查
|
||||
"fail_on_warning": False, # 是否将 WARNING 也视为失败
|
||||
}
|
||||
```
|
||||
|
||||
### 策略预设应用
|
||||
|
||||
在 Stage 2 之前,可以应用策略预设:
|
||||
|
||||
```python
|
||||
# 首次同步:启用自动绑定,双向创建
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("first_sync")
|
||||
|
||||
# 日常同步:仅推送更新
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("push_only")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 关键指标
|
||||
|
||||
在各阶段收集以下指标:
|
||||
|
||||
| 指标 | 含义 |
|
||||
|------|------|
|
||||
| `nodes_loaded` | 加载的节点总数 |
|
||||
| `nodes_bound` | 成功绑定的节点数 |
|
||||
| `nodes_missing` | MISSING 状态的节点数 |
|
||||
| `nodes_abnormal` | ABNORMAL/WARNING 状态的节点数 |
|
||||
| `nodes_created` | CREATE 动作的节点数 |
|
||||
| `nodes_updated` | UPDATE 动作的节点数 |
|
||||
| `sync_success` | 同步成功的节点数 |
|
||||
| `sync_failed` | 同步失败的节点数 |
|
||||
| `errors_count` | 检查发现的 ERROR 数量 |
|
||||
| `warnings_count` | 检查发现的 WARNING 数量 |
|
||||
|
||||
### 日志级别
|
||||
|
||||
```
|
||||
INFO: 流程阶段切换、统计信息
|
||||
DEBUG: 节点级别的详细操作
|
||||
WARN: 检查发现的警告
|
||||
ERROR: 检查发现的错误、异常
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 幂等性保证
|
||||
|
||||
**要求**: 同一个 Collection 的多次同步应该是幂等的。
|
||||
|
||||
**设计保证**:
|
||||
1. **Bind 阶段**: 基于绑定记录判定状态,已绑定的节点不会重复绑定
|
||||
2. **Create 阶段**: 已有绑定的节点(NORMAL)不会重复创建
|
||||
3. **Update 阶段**: 基于 `compute_diff()` 判定,无差异则不执行
|
||||
4. **Sync 阶段**: DataSource 根据 `action` 执行,`action=NONE` 的节点跳过
|
||||
|
||||
**前提条件**:
|
||||
- Binding 记录正确持久化
|
||||
- 节点的 `binding_status` 正确保存和加载
|
||||
- `compute_diff()` 逻辑准确
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
详细的检查规范和状态转换规则,请参考:
|
||||
- [CHECK_SPEC.md](./CHECK_SPEC.md) - 检查点详细规范
|
||||
- [STATE_TRANSITIONS.md](./STATE_TRANSITIONS.md) - 状态转换表
|
||||
|
||||
@@ -0,0 +1,492 @@
|
||||
# 节点生命周期状态转移 (Node Lifecycle State Transitions)
|
||||
|
||||
本文档从一个**单节点视角**出发,完整描述一个 `SyncNode` 从诞生到持久化的全部状态变化。
|
||||
|
||||
> **代码映射**:
|
||||
> - 持久化重置:`sync_system_new/common/state_reset.py` → `NodeStateReset`
|
||||
> - 绑定判定:`sync_system_new/sync_system/decision.py` → `SyncDecisionEngine`
|
||||
> - 策略执行:`sync_system_new/sync_system/strategy.py` → `DefaultSyncStrategy`
|
||||
> - ID 解析:`sync_system_new/sync_system/resolve_ids.py` → `IDResolver`
|
||||
> - 物理同步:`sync_system_new/datasource/datasource.py` → `BaseDataSource`
|
||||
> - Handler 降级:`sync_system_new/domain/*/api_handler.py`
|
||||
|
||||
---
|
||||
|
||||
## 状态字段一览
|
||||
|
||||
| 字段 | 类型 | 含义 | 谁负责设置 |
|
||||
|------|------|------|-----------|
|
||||
| `binding_status` | BindingStatus | 绑定健康状态 | Strategy.bind() |
|
||||
| `action` | SyncAction | 待执行动作 | Strategy.create() / update() |
|
||||
| `status` | SyncStatus | 执行结果状态 | DataSource.sync_all() |
|
||||
| `data_id` | str | 业务主键ID | 数据加载 / DataSource 回填 |
|
||||
| `error` | str \| None | 错误信息 | 各阶段 |
|
||||
|
||||
---
|
||||
|
||||
## 完整生命周期
|
||||
|
||||
### 第一次运行(无持久化数据)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 节点尚不存在 │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
数据源加载 (Stage 1)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 节点诞生 │
|
||||
│ │
|
||||
│ binding_status = UNCHECKED ← Collection 创建节点时的初始值 │
|
||||
│ action = NONE │
|
||||
│ status = PENDING │
|
||||
│ data_id = "abc-123" ← 从数据源获取的业务主键 │
|
||||
│ data = {...} ← 从数据源获取的业务数据 │
|
||||
│ origin_data = {...} ← 同上,原始快照 │
|
||||
│ depend_ids = [] ← 空,待 bind 阶段填充 │
|
||||
│ error = None │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第二次及后续运行(有持久化数据)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 从持久化恢复(原始值) │
|
||||
│ │
|
||||
│ binding_status = NORMAL (上次值) │
|
||||
│ action = UPDATE (上次值) │
|
||||
│ status = SUCCESS (上次值) │
|
||||
│ data_id = "abc-123" │
|
||||
│ error = None (上次值) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
阶段1:加载时重置 (NodeStateReset)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 阶段1重置后 │
|
||||
│ │
|
||||
│ binding_status = UNCHECKED ← 重置(每次重新判定) │
|
||||
│ action = UPDATE ← 保留!(用于阶段2识别 CREATE 失败) │
|
||||
│ status = SUCCESS ← 保留!(不自动重置) │
|
||||
│ data_id = "abc-123" ← 不变 │
|
||||
│ data = None ← 重置(等待数据源覆盖) │
|
||||
│ origin_data = None ← 重置(等待数据源覆盖) │
|
||||
│ error = None ← 清空(避免上次错误干扰) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
阶段2:CREATE 僵尸清理
|
||||
(只影响 action=CREATE 且 status=FAILED 或 data_id="" 的节点)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 阶段2清理后(正常节点) │
|
||||
│ │
|
||||
│ action = NONE ← 全部重置为 NONE,准备进入策略阶段 │
|
||||
│ 其他字段不变 │
|
||||
│ │
|
||||
│ (若为 CREATE 僵尸节点:直接从 Collection 删除 + 解除绑定) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
数据源加载覆盖 (Stage 1 后半)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 数据源加载后 │
|
||||
│ │
|
||||
│ data = {...} ← 数据源最新数据覆盖 │
|
||||
│ origin_data = {...} ← 数据源最新数据覆盖 │
|
||||
│ 其他字段不变 │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bind 阶段状态转移 (Stage 2.1)
|
||||
|
||||
Bind 分三个子阶段顺序执行,每个子阶段只修改 `binding_status`。
|
||||
|
||||
### Phase 1: 核心状态判定
|
||||
|
||||
> **代码**:`_phase_core_state()` → `SyncDecisionEngine.determine_core_status()`
|
||||
|
||||
```
|
||||
输入:binding_status = UNCHECKED
|
||||
|
||||
┌─ 有绑定记录?
|
||||
│
|
||||
┌─────┤
|
||||
│ YES │
|
||||
│ └─── 本地数据 + 远程数据 都健康?
|
||||
│ │
|
||||
│ ┌────┴────┐
|
||||
│ │ YES │ NO
|
||||
│ ▼ ▼
|
||||
│ NORMAL WARNING / ABNORMAL
|
||||
│
|
||||
│ NO
|
||||
└──────────────► MISSING
|
||||
```
|
||||
|
||||
| 输入条件 | binding_status 输出 |
|
||||
|---------|-------------------|
|
||||
| 有绑定,双方数据健康 | **NORMAL** |
|
||||
| 有绑定,自身数据损坏 | **ABNORMAL** |
|
||||
| 有绑定,对方数据损坏 | **WARNING** |
|
||||
| 无绑定记录 | **MISSING** |
|
||||
|
||||
### Phase 2: 依赖检查
|
||||
|
||||
> **代码**:`_phase_dependency_check()` → `_check_dependencies_for_nodes()`
|
||||
|
||||
**仅处理 `binding_status = MISSING` 的节点**,其他状态跳过。
|
||||
|
||||
```
|
||||
输入:binding_status = MISSING
|
||||
|
||||
┌─ 有配置 depend_fields?
|
||||
│
|
||||
┌─────┤
|
||||
│ NO └──► 保持 MISSING(无依赖,直接通过)
|
||||
│
|
||||
│ YES ──► 逐一检查依赖节点:
|
||||
│ │
|
||||
│ ┌────┴────────────────────────┐
|
||||
│ │ 全部依赖节点: │
|
||||
│ │ - 存在? ✅ │
|
||||
│ │ - binding_status=NORMAL? ✅ │
|
||||
│ │ - data_id 非空? ✅ │
|
||||
│ └────┬────────────────────────┘
|
||||
│ │
|
||||
│ ┌────┴────┐
|
||||
│ │ 全通过 │ 任一失败
|
||||
│ ▼ ▼
|
||||
│ MISSING DEPENDENCY_ERROR
|
||||
│ + error = "依赖项不满足: ..."
|
||||
│ + depend_ids 已填充
|
||||
```
|
||||
|
||||
**副作用**:无论检查是否通过,都会填充 `node.depend_ids`。
|
||||
|
||||
### Phase 3: 自动绑定
|
||||
|
||||
> **代码**:`_phase_auto_binding()`
|
||||
|
||||
**仅处理 `binding_status = MISSING` 且依赖已通过的节点**。
|
||||
|
||||
```
|
||||
输入:binding_status = MISSING
|
||||
|
||||
auto_bind = False?
|
||||
└──► MISSING → WARNING("跳过自动绑定,无法确认是否需要创建")
|
||||
|
||||
auto_bind = True:
|
||||
│
|
||||
├─ 业务键字段缺失?
|
||||
│ └──► MISSING → WARNING("缺少业务键字段: ...")
|
||||
│
|
||||
├─ 业务键中 ID 字段解析失败?
|
||||
│ └──► MISSING → DEPENDENCY_ERROR("业务键中的ID字段解析失败")
|
||||
│
|
||||
├─ 去噪后 1:1 匹配?
|
||||
│ └──► MISSING → NORMAL(执行自动绑定,建立绑定记录)
|
||||
│
|
||||
├─ N:0(无远程匹配)?
|
||||
│ ├──► create_enabled = True → MISSING → NORMAL,并 spawn 目标 CREATE 节点(S06)
|
||||
│ └──► create_enabled = False → MISSING → WARNING(孤儿且不允许自动创建,需人工处理)
|
||||
│
|
||||
└─ N:M / 多对多 / 多对一?
|
||||
└──► MISSING → WARNING("存在多个候选节点,无法自动绑定")
|
||||
```
|
||||
|
||||
### Bind 阶段结束后可能的状态
|
||||
|
||||
| binding_status | 后续可执行的操作 |
|
||||
|---------------|----------------|
|
||||
| **NORMAL** | UPDATE(如有差异)|
|
||||
| **MISSING** | CREATE |
|
||||
| **ABNORMAL** | 无(需人工) |
|
||||
| **WARNING** | 无(阻止自动操作) |
|
||||
| **DEPENDENCY_ERROR** | 无(等待依赖修复) |
|
||||
|
||||
---
|
||||
|
||||
## Create 阶段状态转移 (Stage 2.2)
|
||||
|
||||
> **代码**:`create()` → `_add_create_action()`
|
||||
|
||||
> **对齐说明(与状态机配置一致)**:
|
||||
> - create_prepare 的入口仍是源节点 `binding_status = MISSING`。
|
||||
> - 但当前配置下,`N:0 + create_enabled=true` 可以在自动绑定阶段直接把源节点转为 `NORMAL`,并 `emit spawn_target_node_state=S06`。
|
||||
> - 因此“触发创建”的入口有两条:
|
||||
> 1) auto_bind 分支(E08f)直接 spawn;
|
||||
> 2) create_prepare 分支(E09b)在 create 检查成功后 spawn。
|
||||
|
||||
**仅处理 `binding_status = MISSING` 的节点**。
|
||||
|
||||
```
|
||||
输入:源节点 binding_status = MISSING, action = NONE
|
||||
|
||||
┌─ 源节点数据为空?
|
||||
│ └──► 跳过,记录日志
|
||||
│
|
||||
├─ IDResolver.resolve_and_validate() 失败?
|
||||
│ └──► binding_status → DEPENDENCY_ERROR
|
||||
│ error = "创建时依赖 ID 未解析: ..."
|
||||
│
|
||||
└─ 成功 ──► 在目标 Collection 创建新节点
|
||||
│
|
||||
├─ 源节点:
|
||||
│ binding_status → NORMAL("从本地创建到远程")
|
||||
│ action 不变(仍为 NONE)
|
||||
│
|
||||
└─ 新建目标节点:
|
||||
binding_status = NORMAL
|
||||
action = CREATE
|
||||
status = PENDING
|
||||
data_id = ""(待远程返回)
|
||||
data = 已替换 ID 的数据副本
|
||||
│
|
||||
└─ 同时建立绑定记录:local_id ↔ remote_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commit Creates — 物理同步 (Stage 2.3)
|
||||
|
||||
> **代码**:`DataSource.sync_all()` → Handler.create()
|
||||
|
||||
```
|
||||
输入:action = CREATE, status = PENDING
|
||||
|
||||
┌─ Handler 执行 API 调用
|
||||
│
|
||||
├─ 同步 API 成功(200/201)
|
||||
│ └──► status → SUCCESS
|
||||
│ data_id = "remote-xyz"(远程分配的 ID 回填)
|
||||
│ data["id"] = "remote-xyz"(主键字段回写)
|
||||
│
|
||||
├─ 异步 API 提交成功(202)
|
||||
│ └──► status → IN_PROGRESS
|
||||
│ context.task_id = "task-xxx"
|
||||
│ │
|
||||
│ └─ 轮询结果:
|
||||
│ ├─ 成功 → status → SUCCESS, data_id 回填
|
||||
│ ├─ 失败 → status → FAILED, error = "..."
|
||||
│ └─ 超时 → status → FAILED, error = "Timeout"
|
||||
│
|
||||
└─ API 失败(4xx/5xx)
|
||||
└──► status → FAILED
|
||||
error = "远程操作失败: ..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Update 阶段状态转移 (Stage 2.4)
|
||||
|
||||
> **代码**:`update()` → `_add_update_action()`
|
||||
|
||||
> **对齐说明**:图里的 `E12a` 从 `S01` 出发并不矛盾。`S01` 约束的是“源节点”有 `data_id`;
|
||||
> `E12a` 检查的是“目标节点”是否有 `data_id`(guard: `target_has_data_id=false`),两者不是同一个对象。
|
||||
|
||||
**过滤条件**:`binding_status = NORMAL` 且 `status != FAILED`
|
||||
|
||||
```
|
||||
输入:源节点 binding_status = NORMAL, action = NONE
|
||||
|
||||
┌─ status == FAILED?
|
||||
│ └──► 跳过(保护上次失败的状态和错误信息)
|
||||
│
|
||||
├─ 源节点数据为空?
|
||||
│ └──► 跳过
|
||||
│
|
||||
├─ 通过绑定找不到目标节点?
|
||||
│ └──► 跳过,记录日志
|
||||
│
|
||||
├─ 目标节点 data_id 为空?
|
||||
│ └──► 目标节点 status → PRECONDITION_FAILED
|
||||
│ ("目标节点缺少 data_id")
|
||||
│
|
||||
├─ IDResolver.resolve_and_validate() 失败?
|
||||
│ └──► 目标节点 action → UPDATE
|
||||
│ 目标节点 status → PRECONDITION_FAILED
|
||||
│ 目标节点 error = "依赖 ID 未解析: ..."
|
||||
│
|
||||
├─ _needs_update() 判定无差异?
|
||||
│ └──► 跳过(不设置 action)
|
||||
│
|
||||
└─ 有差异 ──► 更新目标节点:
|
||||
action → UPDATE
|
||||
status → PENDING
|
||||
data = 已替换 ID 的数据副本
|
||||
error = None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commit Updates — 物理同步 (Stage 2.5)
|
||||
|
||||
> **代码**:`DataSource.sync_all()` → Handler.update()
|
||||
|
||||
```
|
||||
输入:action = UPDATE, status = PENDING
|
||||
|
||||
┌─ Handler 构建 API 请求
|
||||
│
|
||||
├─ Handler 发现无实际变更字段
|
||||
│ └──► action → NONE(Handler 降级,不提交 API)
|
||||
│
|
||||
├─ 同步 API 成功(200)
|
||||
│ └──► status → SUCCESS
|
||||
│
|
||||
├─ 异步 API 提交成功(202)
|
||||
│ └──► status → IN_PROGRESS → (轮询)→ SUCCESS / FAILED
|
||||
│
|
||||
└─ API 失败
|
||||
└──► status → FAILED
|
||||
error = "远程操作失败: ..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 持久化阶段 (Stage 5)
|
||||
|
||||
```
|
||||
节点当前状态原样写入存储。
|
||||
|
||||
持久化字段:
|
||||
✅ node_id, data_id, data, origin_data
|
||||
✅ binding_status, action, status, error, context
|
||||
❌ depend_ids(不持久化,下次 bind 时从 data 实时计算)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 全景时间线表
|
||||
|
||||
下表展示**一个节点在典型场景中的状态变化**:
|
||||
|
||||
### 场景 A:首次创建(本地 → 远程)
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| 数据加载 | UNCHECKED | NONE | PENDING | "abc-123" | None |
|
||||
| bind phase1 | **MISSING** | NONE | PENDING | "abc-123" | None |
|
||||
| bind phase2 | MISSING | NONE | PENDING | "abc-123" | None |
|
||||
| bind phase3 | MISSING | NONE | PENDING | "abc-123" | None |
|
||||
| create | **NORMAL** | NONE | PENDING | "abc-123" | None |
|
||||
| _(新建远程节点)_ | NORMAL | **CREATE** | PENDING | **""** | None |
|
||||
| commit create | NORMAL | CREATE | **SUCCESS** | **"remote-456"** | None |
|
||||
| 持久化 | NORMAL | CREATE | SUCCESS | "remote-456" | None |
|
||||
|
||||
### 场景 B:日常更新
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| 持久化恢复 | NORMAL→**UNCHECKED** | CREATE→保留 | SUCCESS→保留 | "abc-123" | 清空 |
|
||||
| 阶段2 action重置 | UNCHECKED | **NONE** | SUCCESS | "abc-123" | None |
|
||||
| 数据源覆盖 | UNCHECKED | NONE | SUCCESS | "abc-123" | None |
|
||||
| bind phase1 | **NORMAL** | NONE | SUCCESS | "abc-123" | None |
|
||||
| update 检测差异 | NORMAL | NONE | SUCCESS | "abc-123" | None |
|
||||
| _(目标节点)_ | NORMAL | **UPDATE** | **PENDING** | "remote-456" | None |
|
||||
| commit update | NORMAL | UPDATE | **SUCCESS** | "remote-456" | None |
|
||||
|
||||
### 场景 C:依赖阻断
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| 数据加载 | UNCHECKED | NONE | PENDING | "contract-789" | None |
|
||||
| bind phase1 | **MISSING** | NONE | PENDING | "contract-789" | None |
|
||||
| bind phase2 | **DEPENDENCY_ERROR** | NONE | PENDING | "contract-789" | "依赖项不满足: project_id: 状态=dep_err" |
|
||||
| _(后续阶段不处理)_ | | | | | |
|
||||
| 持久化 | DEPENDENCY_ERROR | NONE | PENDING | "contract-789" | "依赖项不满足..." |
|
||||
|
||||
### 场景 D:CREATE 失败 → 下次自动恢复
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| **第 1 次运行** | | | | | |
|
||||
| create | NORMAL | CREATE | PENDING | "" | None |
|
||||
| commit create 失败 | NORMAL | CREATE | **FAILED** | "" | "远程操作失败: 500" |
|
||||
| 持久化 | NORMAL | CREATE | FAILED | "" | "远程操作失败: 500" |
|
||||
| **第 2 次运行** | | | | | |
|
||||
| 阶段1恢复 | **UNCHECKED** | CREATE | FAILED | "" | **None** |
|
||||
| 阶段2僵尸清理 | _(节点被删除,绑定被解除)_ | | | | |
|
||||
| 数据源重新加载 | UNCHECKED | NONE | PENDING | "" → 新 node_id | None |
|
||||
| bind → create | 重新走首次创建流程 | | | | |
|
||||
|
||||
### 场景 E:UPDATE 失败 → 保留供人工处理
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| **第 1 次运行** | | | | | |
|
||||
| update | NORMAL | UPDATE | PENDING | "remote-456" | None |
|
||||
| commit update 失败 | NORMAL | UPDATE | **FAILED** | "remote-456" | "403 Forbidden" |
|
||||
| 持久化 | NORMAL | UPDATE | FAILED | "remote-456" | "403 Forbidden" |
|
||||
| **第 2 次运行** | | | | | |
|
||||
| 阶段1恢复 | UNCHECKED | UPDATE | FAILED | "remote-456" | None |
|
||||
| 阶段2 action重置 | UNCHECKED | **NONE** | **FAILED** | "remote-456" | None |
|
||||
| bind | NORMAL | NONE | FAILED | "remote-456" | None |
|
||||
| update 跳过 | _(status=FAILED,自动跳过)_ | | | | |
|
||||
| 持久化 | NORMAL | NONE | FAILED | "remote-456" | None |
|
||||
| _(需人工重置 status 后才能重新更新)_ | | | | | |
|
||||
|
||||
---
|
||||
|
||||
## 状态转换合法性约束
|
||||
|
||||
### binding_status 允许的转换
|
||||
|
||||
```
|
||||
UNCHECKED → NORMAL (核心判定: 有绑定且健康)
|
||||
UNCHECKED → MISSING (核心判定: 无绑定记录)
|
||||
UNCHECKED → ABNORMAL (核心判定: 自身数据损坏)
|
||||
UNCHECKED → WARNING (核心判定: 对方数据损坏)
|
||||
|
||||
MISSING → DEPENDENCY_ERROR (依赖检查: 父节点不满足)
|
||||
MISSING → WARNING (自动绑定: 业务键缺失 / 多候选 / auto_bind=False)
|
||||
MISSING → DEPENDENCY_ERROR (自动绑定: ID 字段解析失败)
|
||||
MISSING → NORMAL (自动绑定: 1:1 成功)
|
||||
MISSING → NORMAL (create: 源节点创建成功后)
|
||||
MISSING → DEPENDENCY_ERROR (create: ID 解析失败)
|
||||
```
|
||||
|
||||
> **注意**:当前 `SyncNode.set_binding_status()` 不做转换合法性校验【未实现】。
|
||||
|
||||
### action 允许的转换
|
||||
|
||||
```
|
||||
NONE → CREATE (create: 新建目标节点)
|
||||
NONE → UPDATE (update: 检测到差异)
|
||||
UPDATE → NONE (Handler 降级: 实际无变更字段)
|
||||
```
|
||||
|
||||
### status 允许的转换
|
||||
|
||||
```
|
||||
PENDING → IN_PROGRESS (DataSource: 异步提交成功)
|
||||
PENDING → SUCCESS (DataSource: 同步执行成功)
|
||||
PENDING → FAILED (DataSource: 执行失败)
|
||||
PENDING → SKIPPED (DataSource: 被跳过)
|
||||
(常见于 CREATE/UPDATE:Handler 返回 SKIPPED(无可执行操作/业务条件不满足),对应状态机里的 E19→S13 或 E20→S14)
|
||||
PENDING → PRECONDITION_FAILED (Strategy: 前置条件不满足)
|
||||
IN_PROGRESS → SUCCESS (DataSource: 异步轮询成功)
|
||||
IN_PROGRESS → FAILED (DataSource: 异步轮询失败/超时)
|
||||
```
|
||||
|
||||
> **注意**:当前 `SyncNode.set_status()` 不做转换合法性校验【未实现】。
|
||||
|
||||
---
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [状态定义规范](./状态定义规范.md) — 状态枚举和判定规则
|
||||
- [持久化与人工介入规范](./持久化与人工介入规范.md) — 持久化重置策略
|
||||
- [编排流程规范](./编排流程规范.md) — Pipeline 阶段定义
|
||||
- [架构分层设计](./架构分层设计.md) — 各层职责
|
||||
- [node_id_data_id_lifecycle](./node_id_data_id_lifecycle.md) — ID 生命周期
|
||||
@@ -0,0 +1,14 @@
|
||||
# Root docs migration note
|
||||
|
||||
本目录为从项目根目录 `docs/` 迁移过来的文档快照(全量复制,不跳过)。
|
||||
|
||||
目的:
|
||||
- 保留原始设计背景与历史规范,便于在 `sync_state_machine` 目录内就地查阅;
|
||||
- 与当前 `sync_state_machine/docs/` 的“现行实现文档”并存。
|
||||
|
||||
使用建议:
|
||||
- 以 `sync_state_machine/docs/` 下现行文档(如 `state_machine.md`、`sync_flow.md`、`architecture.md`)作为运行时真义;
|
||||
- 本目录文档作为历史参考来源,遇到冲突时以现行实现与状态机配置为准:
|
||||
- `sync_state_machine/config/node_state_machine.yaml`
|
||||
- `sync_state_machine/sync_system/strategy.py`
|
||||
- `sync_state_machine/engine/semantics.py`
|
||||
@@ -0,0 +1,706 @@
|
||||
# API DataSource 架构设计
|
||||
|
||||
## 架构总览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Pipeline │
|
||||
│ (同步流程编排) │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ApiDataSource │
|
||||
│ (数据源协调层) │
|
||||
│ │
|
||||
│ - 持有 ApiClient 实例 │
|
||||
│ - 注册和管理 Handler │
|
||||
│ - 实现 load_all / execute_batch │
|
||||
│ - 注入 api_client 到 Handler │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ Handler │ │ Handler │ │ Handler │
|
||||
│ Project │ │ Contract │ │ Material │
|
||||
│ │ │ │ │ │
|
||||
│ 业务逻辑层 │ │ 业务逻辑层 │ │ 业务逻辑层 │
|
||||
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
||||
│ │ │
|
||||
└───────────────────┼───────────────────┘
|
||||
│ 使用 self.api_client
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ ApiClient │
|
||||
│ (HTTP 通信层) │
|
||||
│ │
|
||||
│ - 签名生成 │
|
||||
│ - HTTP 请求 │
|
||||
│ - Push Log │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
**调用流程**:
|
||||
1. Pipeline 创建 ApiDataSource,传入 base_url, uid, secret
|
||||
2. ApiDataSource 内部创建 ApiClient 实例
|
||||
3. ApiDataSource 注册各业务 Handler,并注入 api_client
|
||||
4. Handler 使用 `self.api_client.get/post/put()` 发送请求
|
||||
5. ApiClient 自动处理签名、push_log 查询、错误处理
|
||||
|
||||
**优势**:
|
||||
- ✅ **职责清晰**:ApiClient(通信)、DataSource(协调)、Handler(业务)
|
||||
- ✅ **避免循环依赖**:Handler → ApiClient(单向依赖)
|
||||
- ✅ **易于测试**:ApiClient 可 mock,Handler 独立测试
|
||||
- ✅ **易于扩展**:新业务只需实现 Handler
|
||||
|
||||
## 1. 问题分析:旧方案的复杂性
|
||||
|
||||
旧方案 `sync_system/datasource/api` 存在的问题:
|
||||
|
||||
1. **过度抽象**:引入了 `ApiDataSource` → `Repository` → `ResponseHandle` → `Cache` 多层封装,每个业务需要独立 Repository 类,Protocol 定义繁琐
|
||||
2. **状态管理混乱**:缓存策略不清晰,ResponseHandle 封装异步结果但使用困难,缺少统一的 push_log 查询机制
|
||||
3. **依赖关系困难**:Repository 之间互相传递引用,难以从 collection 获取已有数据
|
||||
4. **API 路由分散**:每个 Repository 手动实现多个 update 方法,缺少自动路由机制
|
||||
|
||||
## 2. 新方案设计原则
|
||||
|
||||
- **简单直接**:Handler 直接调用 HTTP API,不过度封装
|
||||
- **状态透明**:DataSource 统一管理 session、签名、push_log 查询
|
||||
- **依赖清晰**:通过 collection 获取依赖数据,使用 context 存储额外信息
|
||||
- **智能路由**:根据数据字段自动选择 API endpoint
|
||||
|
||||
## 3. 核心组件职责
|
||||
|
||||
### 3.1 ApiClient - HTTP 通信层
|
||||
|
||||
**职责**:
|
||||
- 封装所有 HTTP 通信逻辑
|
||||
- 管理 httpx.AsyncClient,维护连接池和 session
|
||||
- 生成请求签名(timestamp, nonce, sign)
|
||||
- 统一请求入口,自动注入 uid
|
||||
- 批量 Push Log 查询
|
||||
|
||||
**核心方法**:
|
||||
```python
|
||||
class ApiClient:
|
||||
def __init__(self, base_url: str, uid: str, secret: str):
|
||||
self._client = httpx.AsyncClient()
|
||||
self._base_url = base_url
|
||||
self._uid = uid
|
||||
self._secret = secret
|
||||
|
||||
async def request(self, method: str, url: str, **kwargs) -> httpx.Response
|
||||
"""统一请求入口,自动签名"""
|
||||
|
||||
async def get(self, url: str, params: dict = None) -> httpx.Response
|
||||
"""GET 请求"""
|
||||
|
||||
async def post(self, url: str, data: dict) -> httpx.Response
|
||||
"""POST 请求,data 中已包含 push_id/biz_id(由 Handler 生成)"""
|
||||
|
||||
async def put(self, url: str, data: dict) -> httpx.Response
|
||||
"""PUT 请求,data 中已包含 push_id/biz_id"""
|
||||
|
||||
async def delete(self, url: str, data: dict) -> httpx.Response
|
||||
"""DELETE 请求,data 中已包含 push_id/biz_id"""
|
||||
|
||||
async def get_push_logs(self, push_ids: List[str]) -> Dict[str, dict]
|
||||
"""批量查询 push_log 状态,返回 {push_id: push_log_data}
|
||||
注意:单个查询也传单元素列表
|
||||
当前实现:用 for 循环模拟,后续等后端实现批量接口
|
||||
"""
|
||||
|
||||
def _generate_signature(self, params: dict) -> dict
|
||||
"""生成签名参数(timestamp, nonce, sign)"""
|
||||
```
|
||||
|
||||
### 3.2 ApiDataSource - 数据源协调层
|
||||
|
||||
**职责**:
|
||||
- 持有 ApiClient 实例,提供给 Handler 使用
|
||||
- 实现 DataSource 接口(load_all, sync_all)
|
||||
- 协调多个 Handler 的执行顺序(通过 sync_all)
|
||||
- Handler 内部负责:生成 push_id/biz_id、调用 poll 轮询、提取 created_id
|
||||
- 统一异常处理和日志记录
|
||||
|
||||
**核心属性和方法**:
|
||||
```python
|
||||
class ApiDataSource(DataSource):
|
||||
def __init__(self, base_url: str, uid: str, secret: str):
|
||||
self.client = ApiClient(base_url, uid, secret)
|
||||
self._handlers: Dict[str, BaseApiHandler] = {}
|
||||
|
||||
def register_handler(self, node_type: str, handler: BaseApiHandler):
|
||||
"""注册业务 Handler"""
|
||||
handler.api_client = self.client # 注入 client
|
||||
self._handlers[node_type] = handler
|
||||
|
||||
async def load_all(self, collection: DataCollection, order: List[str]) -> None:
|
||||
"""调用基类的 load_all,按顺序加载数据"""
|
||||
|
||||
async def sync_all(self, collection: DataCollection, order: List[str]) -> None:
|
||||
"""调用基类的 sync_all,按顺序执行同步"""
|
||||
```
|
||||
|
||||
### 3.3 BaseApiHandler - 业务逻辑基类
|
||||
|
||||
**职责**:
|
||||
- 实现 Handler 接口(load, create, update, delete, poll)
|
||||
- 使用 self.api_client 发送 HTTP 请求
|
||||
- 生成 push_id 和 biz_id(业务标识)
|
||||
- 从 collection 获取依赖节点数据
|
||||
- 管理节点的 context(存储 project_id, contract_id 等)
|
||||
- 实现 poll 方法,调用 api_client.get_push_logs 批量查询
|
||||
- 提取 created_id(因为不同业务的 id 字段名和位置可能不同)
|
||||
- 返回 TaskResult(SUCCESS/FAILED/IN_PROGRESS)
|
||||
|
||||
**核心方法**:
|
||||
```python
|
||||
class BaseApiHandler(NodeHandler):
|
||||
def __init__(self):
|
||||
self.api_client: ApiClient = None # 由 DataSource 注入
|
||||
self.collection: DataCollection = None # 由 DataSource 注入
|
||||
|
||||
async def load(self, collection: DataCollection) -> List[dict]
|
||||
async def create(self, node: SyncNode) -> TaskResult
|
||||
async def update(self, node: SyncNode) -> TaskResult
|
||||
async def delete(self, node: SyncNode) -> TaskResult
|
||||
async def poll(self, node: SyncNode, task_id: str) -> TaskResult
|
||||
|
||||
def extract_created_id(self, push_log: dict) -> str
|
||||
"""从 push_log 提取 created_id,子类可重写"""
|
||||
|
||||
# 重试逻辑(可选,子类可重写)
|
||||
async def _execute_with_retry(self, operation, max_retries: int = 3) -> Any
|
||||
"""通用重试逻辑,子类可自定义重试策略"""
|
||||
```
|
||||
|
||||
**重试策略说明**:
|
||||
- **重试在 Handler 内部**:create/update/delete 内部可调用 _execute_with_retry
|
||||
- **返回给 DataSource**:最终只返回 SUCCESS/FAILED/IN_PROGRESS
|
||||
- **灵活控制**:不同业务可重写 _execute_with_retry 实现自定义策略
|
||||
- **默认策略**:网络错误/5xx 重试 3 次,4xx 不重试
|
||||
|
||||
**未实现 API 的处理**:
|
||||
- 部分业务可能没有实现 create 或 delete API
|
||||
- 此时 Handler 应在对应方法中直接返回 FAILED 状态,并在 error 中说明原因
|
||||
- 示例:`return TaskResult(status=TaskStatus.FAILED, error="Create API not implemented for this business")`
|
||||
|
||||
### 3.4 具体业务 Handler
|
||||
|
||||
**职责**:
|
||||
- 实现具体业务的 load 逻辑(调用 self.api_client.get())
|
||||
- 创建节点时设置 context
|
||||
- 重写 API endpoint 选择逻辑(可选)
|
||||
- 定制 created_id 提取逻辑(可选)
|
||||
|
||||
每个业务 Handler 位于 `sync_system_new/domain/{业务}/api_handler.py`
|
||||
|
||||
## 4. HTTP 请求状态管理
|
||||
|
||||
### 4.0 状态系统概述
|
||||
|
||||
**通用状态枚举**(适用于所有 DataSource):
|
||||
|
||||
```python
|
||||
class TaskStatus(Enum):
|
||||
"""Handler 返回的任务执行状态"""
|
||||
SUCCESS = "success" # 同步完成,立即成功
|
||||
FAILED = "failed" # 同步失败
|
||||
IN_PROGRESS = "in_progress" # 异步任务进行中
|
||||
|
||||
class SyncStatus(Enum):
|
||||
"""SyncNode 的同步执行状态"""
|
||||
PENDING = "PENDING"
|
||||
IN_PROGRESS = "IN_PROGRESS"
|
||||
SUCCESS = "SUCCESS"
|
||||
FAILED = "FAILED"
|
||||
SKIPPED = "SKIPPED"
|
||||
PRECONDITION_FAILED = "PRECONDITION_FAILED"
|
||||
```
|
||||
|
||||
**状态映射规则**:
|
||||
- TaskStatus 是 Handler 执行操作后的返回值
|
||||
- SyncStatus 是 SyncNode 的最终状态,由 DataSource 根据 TaskStatus 更新
|
||||
- 普通 DataSource(FileDataSource)和 API DataSource 使用相同的状态枚举
|
||||
- 区别在于:**API DataSource 的网络操作如何转化为 TaskStatus**
|
||||
|
||||
**重要说明:Load 阶段 vs 执行阶段的状态**:
|
||||
- **Load 阶段**(Handler.load()):从 API 拉取数据创建 SyncNode
|
||||
- 此时节点状态为 `PENDING`(等待后续 bind/create/update)
|
||||
- GET 请求失败不影响节点创建,只是该节点不存在于 collection
|
||||
- **执行阶段**(Handler.create/update/delete):执行同步操作
|
||||
- DataSource 在调用前设置 `node.status = IN_PROGRESS`
|
||||
- Handler 返回 TaskResult,DataSource 据此更新 node.status
|
||||
- POST/PUT/DELETE 成功后才设置为 SUCCESS
|
||||
|
||||
**核心映射逻辑**(在 DataSource 中):
|
||||
```python
|
||||
# 执行前:DataSource 设置状态
|
||||
node.status = SyncStatus.IN_PROGRESS
|
||||
|
||||
# 调用 Handler(Handler 内部可能重试多次)
|
||||
result = await handler.create(node)
|
||||
|
||||
# 执行后:DataSource 根据最终结果更新状态
|
||||
if result.status == TaskStatus.SUCCESS:
|
||||
node.status = SyncStatus.SUCCESS
|
||||
node.data_id = result.data_id
|
||||
elif result.status == TaskStatus.FAILED:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = result.error
|
||||
elif result.status == TaskStatus.IN_PROGRESS:
|
||||
# 记录 task_id 等待轮询
|
||||
async_tasks[node.node_id] = result.task_id
|
||||
```
|
||||
|
||||
**重要**:Handler 负责重试,最终只返回确定的结果(SUCCESS/FAILED/IN_PROGRESS)
|
||||
|
||||
### 4.1 请求类型与状态流转
|
||||
|
||||
**API DataSource 的特殊性**:
|
||||
- **Load 阶段**:GET 请求拉取数据,创建 PENDING 节点(失败则不创建节点)
|
||||
- **执行阶段**:POST/PUT/DELETE 先设置 IN_PROGRESS,通过 poll() 轮询变为 SUCCESS/FAILED
|
||||
|
||||
#### Load 阶段 - 数据拉取
|
||||
|
||||
**目的**:从 API 获取数据,创建 SyncNode 放入 collection
|
||||
|
||||
| 阶段 | HTTP 操作 | 成功行为 | 失败行为 | 节点状态 |
|
||||
|------|----------|---------|---------|---------|
|
||||
| 1. 调用 load() | GET /api/list | 返回数据列表 | 返回空列表或抛异常 | - |
|
||||
| 2. 创建节点 | - | 为每条数据创建 SyncNode | 不创建节点 | PENDING |
|
||||
|
||||
**代码示例**:
|
||||
```python
|
||||
async def load(self, collection: DataCollection) -> List[dict]:
|
||||
"""加载数据 - GET 阶段不涉及状态转换"""
|
||||
try:
|
||||
response = await self.api_client.get("project/list")
|
||||
if response.status_code == 200:
|
||||
data_list = response.json().get("list", [])
|
||||
# 返回数据,由 DataSource 创建 PENDING 节点
|
||||
return data_list
|
||||
else:
|
||||
# 失败:返回空列表,不创建节点
|
||||
logger.error(f"Load failed: {response.status_code}")
|
||||
return []
|
||||
except Exception as e:
|
||||
logger.error(f"Load exception: {e}")
|
||||
return [] # 或者抛出异常,由调用方处理
|
||||
```
|
||||
|
||||
#### Mutation 请求(POST/PUT/DELETE) - 执行阶段
|
||||
|
||||
**状态变化时机**:
|
||||
1. **执行前**:DataSource 设置 `node.status = IN_PROGRESS`
|
||||
2. **Handler 执行**:内部可能重试,最终返回 SUCCESS/FAILED/IN_PROGRESS
|
||||
3. **轮询完成**:poll() 返回 SUCCESS/FAILED
|
||||
|
||||
| 阶段 | Push Log | TaskStatus | SyncStatus | 说明 |
|
||||
|------|---------|-----------|-----------|------|
|
||||
| 执行前 | - | - | PENDING → IN_PROGRESS | DataSource 设置 |
|
||||
| 提交 | pending | IN_PROGRESS | IN_PROGRESS | 任务已提交 |
|
||||
| 轮询 | processing | IN_PROGRESS | IN_PROGRESS | 后端处理中 |
|
||||
| 成功 | success | SUCCESS | SUCCESS | 同步完成 |
|
||||
| 失败 | failed | FAILED | FAILED | 同步失败 |
|
||||
|
||||
**示例**:
|
||||
```python
|
||||
async def create(self, node: SyncNode) -> TaskResult:
|
||||
"""Handler 内部可重试,最终返回确定结果"""
|
||||
response = await self.api_client.post(url, node.data)
|
||||
if response.status_code == 202:
|
||||
return TaskResult.in_progress(task_id=response.json()["push_id"])
|
||||
else:
|
||||
return TaskResult.failed(error=f"HTTP {response.status_code}")
|
||||
|
||||
async def poll(self, node: SyncNode, task_id: str) -> TaskResult:
|
||||
push_logs = await self.api_client.get_push_logs([task_id])
|
||||
status = push_logs.get(task_id, {}).get("status")
|
||||
if status == "success":
|
||||
return TaskResult.success(data_id=self.extract_created_id(push_logs[task_id]))
|
||||
elif status == "failed":
|
||||
return TaskResult.failed(error="Backend processing failed")
|
||||
else:
|
||||
return TaskResult.in_progress(task_id=task_id)
|
||||
```
|
||||
|
||||
### 4.2 状态转换完整流程
|
||||
|
||||
```
|
||||
Load 阶段:
|
||||
Handler.load() → 返回数据列表 → DataSource 创建 PENDING 节点
|
||||
|
||||
执行阶段(同步操作):
|
||||
DataSource: node.status = IN_PROGRESS
|
||||
→ Handler.create() → TaskResult.success/failed()
|
||||
→ DataSource: node.status = SUCCESS/FAILED
|
||||
|
||||
执行阶段(异步操作):
|
||||
DataSource: node.status = IN_PROGRESS
|
||||
→ Handler.create() → TaskResult.in_progress(push_id)
|
||||
→ DataSource 轮询: Handler.poll(push_id)
|
||||
→ TaskResult.success/failed()
|
||||
→ DataSource: node.status = SUCCESS/FAILED
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- Handler 负责重试,DataSource 只处理最终结果
|
||||
- 不同业务可在 BaseApiHandler._execute_with_retry 中自定义重试策略
|
||||
- FileDataSource 和 ApiDataSource 使用相同的状态枚举和转换逻辑
|
||||
|
||||
### 4.3 Push Log 状态机
|
||||
|
||||
```
|
||||
pending → processing → success/failed
|
||||
```
|
||||
|
||||
- 轮询间隔:0.5秒
|
||||
- 超时:30秒
|
||||
- 成功:提取 created_id
|
||||
- 失败:获取 error_message
|
||||
|
||||
### 4.4 状态总结表
|
||||
|
||||
**Load 阶段(数据拉取)**:
|
||||
|
||||
| HTTP 操作 | 响应码 | 行为 | 创建节点 | 节点状态 | 说明 |
|
||||
|---------|-------|-----|---------|---------|------|
|
||||
| GET /list | 200 | 返回数据列表 | ✅ 是 | PENDING | 等待后续 bind/create/update |
|
||||
| GET /list | 4xx/5xx | 返回空列表 | ❌ 否 | - | 不创建节点 |
|
||||
|
||||
**执行阶段(POST/PUT/DELETE)**:
|
||||
|
||||
| HTTP 操作 | 响应码 | Push Log | TaskStatus | SyncStatus | 说明 |
|
||||
|---------|-------|---------|-----------|-----------|------|
|
||||
| POST/PUT | 202 | pending | IN_PROGRESS | IN_PROGRESS | 异步开始 |
|
||||
| - | - | processing | IN_PROGRESS | IN_PROGRESS | 异步处理中 |
|
||||
| - | - | success | SUCCESS | SUCCESS | 异步成功 |
|
||||
| - | - | failed | FAILED | FAILED | 异步失败 |
|
||||
| - | - | timeout | FAILED | FAILED | 轮询超时 |
|
||||
|
||||
## 5. Context 机制
|
||||
|
||||
### 5.1 Context 的作用
|
||||
|
||||
Context 是 SyncNode 的字典字段,用于存储业务数据之外的上下文信息,例如:
|
||||
- `project_id`: 当前对象所属的项目ID
|
||||
- `contract_id`: 合同变更所属的合同ID
|
||||
- `parent_id`: 父对象ID
|
||||
- 其他 API 调用需要但 schema 中没有的信息
|
||||
|
||||
### 5.2 Context 使用流程
|
||||
|
||||
**场景:加载合同数据**
|
||||
|
||||
1. **Handler.load()** 从 self._collection 获取所有 project
|
||||
2. 遍历每个 project,调用 `GET contract/list?project_id=xxx`
|
||||
3. 为每个返回的 contract 数据添加临时标记 `_context = {"project_id": xxx}`
|
||||
4. **Handler.create_node()** 创建 SyncNode 时,提取 `_context` 并设置到 `node.context`
|
||||
5. **Handler.update()** 更新时,从 `node.context["project_id"]` 获取 project_id 并添加到请求数据
|
||||
|
||||
### 5.3 Context 传递规则
|
||||
|
||||
- 父 → 子:从依赖的父节点继承 context
|
||||
- 横向传递:同级节点不共享 context
|
||||
- 更新时使用:从 context 提取必要信息添加到请求 payload
|
||||
|
||||
## 6. 智能 API 路由
|
||||
|
||||
### 6.1 路由策略
|
||||
|
||||
根据节点数据的字段,自动选择正确的 API endpoint:
|
||||
|
||||
**方案1:字段匹配**
|
||||
- 检查 node.data 中的字段集合
|
||||
- 匹配预定义的 endpoint → required_fields 映射表
|
||||
- 选择第一个匹配的 endpoint
|
||||
|
||||
**方案2:Schema 类型**
|
||||
- 根据 node.schema 的类型
|
||||
- 查找 schema_type → endpoint 映射表
|
||||
|
||||
**默认规则**:
|
||||
- CREATE: `{node_type}`
|
||||
- UPDATE: 子类重写 `_select_update_endpoint()`
|
||||
- DELETE: `{node_type}`
|
||||
|
||||
### 6.2 Project 示例
|
||||
|
||||
Project 有多个更新接口:
|
||||
- `project/key_constraints` - 需要字段:key_constraints, key_constraints_remark
|
||||
- `project/complete_investment` - 需要字段:complete_investment
|
||||
- `project/dynamic_investment` - 需要字段:dynamic_investment
|
||||
- `project/plan_construction` - 需要字段:plan_construction_capacity, plan_construction_date
|
||||
- ... 等
|
||||
|
||||
Handler 定义映射表,根据实际数据字段自动选择。
|
||||
|
||||
## 7. 依赖数据获取
|
||||
|
||||
### 7.1 获取模式
|
||||
|
||||
Handler 通过 `collection.filter(node_type="xxx")` 获取依赖数据:
|
||||
|
||||
**加载顺序**(按依赖关系):
|
||||
1. Project(无依赖)
|
||||
2. Contract(依赖 Project)
|
||||
3. Contract Change(依赖 Project + Contract)
|
||||
|
||||
### 7.2 数据流
|
||||
|
||||
```
|
||||
Pipeline
|
||||
→ 按拓扑序加载
|
||||
→ ProjectHandler.load()
|
||||
→ GET project/list
|
||||
→ 创建 ProjectSyncNode
|
||||
→ ContractHandler.load()
|
||||
→ collection.filter(node_type="project")
|
||||
→ 遍历 project,GET contract/list?project_id=xxx
|
||||
→ 创建 ContractSyncNode,设置 context["project_id"]
|
||||
→ ContractChangeHandler.load()
|
||||
→ collection.filter(node_type="contract")
|
||||
→ 遍历 contract,从 context 获取 project_id
|
||||
→ GET contract_change/list?project_id=xxx&contract_id=yyy
|
||||
→ 创建节点,设置 context
|
||||
```
|
||||
|
||||
## 8. 实现计划
|
||||
|
||||
### Phase 1: HTTP 通信层
|
||||
- 实现 **ApiClient** 类
|
||||
- HTTP Client 封装(httpx.AsyncClient)
|
||||
- 签名生成(_generate_signature)
|
||||
- 统一请求方法(get/post/put/delete)
|
||||
- **批量 Push Log 查询**(get_push_logs,单个也传列表)
|
||||
- ~~wait_for_push_log~~(不实现,由 DataSource 调用 poll)
|
||||
|
||||
### Phase 2: DataSource 协调层
|
||||
- 实现 **ApiDataSource** 类
|
||||
- 持有 ApiClient 实例
|
||||
- Handler 注册和管理
|
||||
- 实现 DataSource 接口(load_all, execute_batch)
|
||||
- 注入 api_client 到 Handler
|
||||
- 实现轮询逻辑(_poll_async_tasks)
|
||||
|
||||
### Phase 3: Handler 基类
|
||||
- 实现 **BaseApiHandler** 类
|
||||
- load/create/update/delete/poll 方法
|
||||
- 使用 self.api_client 发送请求
|
||||
- **extract_created_id**(子类可重写)
|
||||
- **_execute_with_retry**(可选,子类可重写重试策略)
|
||||
- Context 管理
|
||||
|
||||
### Phase 4: 业务验证
|
||||
- 实现 **ProjectApiHandler**(无依赖,简单场景)
|
||||
- 实现 load:GET project/list
|
||||
- 实现 create:POST project
|
||||
- 实现 poll:查询 push_log
|
||||
- 实现 **ContractApiHandler**(依赖 Project,验证 context)
|
||||
- 实现 load:遍历 project,GET contract/list?project_id=xxx
|
||||
- 设置 context["project_id"]
|
||||
- 编写测试验证设计
|
||||
|
||||
### Phase 5: 完善功能
|
||||
- 批量 Push Log 查询优化(等待后端实现批量接口)
|
||||
- 超时控制(可配置)
|
||||
- 请求日志和调试
|
||||
|
||||
### Phase 6: 推广
|
||||
- 实现剩余业务 Handler
|
||||
- 性能优化(并发控制)
|
||||
- 文档和示例
|
||||
|
||||
## 9. 与现有系统集成
|
||||
|
||||
**调用关系**:
|
||||
```
|
||||
Pipeline
|
||||
↓
|
||||
ApiDataSource (持有 ApiClient)
|
||||
↓
|
||||
BaseApiHandler (使用 api_client)
|
||||
↓
|
||||
ApiClient (发送 HTTP 请求)
|
||||
```
|
||||
|
||||
**职责分离**:
|
||||
- **ApiClient**: 纯粹的 HTTP 通信,无业务逻辑
|
||||
- **ApiDataSource**: 协调 Handler,管理执行流程
|
||||
- **BaseApiHandler**: 业务逻辑,调用 ApiClient 完成网络操作
|
||||
- **具体 Handler**: 实现特定业务的 load/create/update/delete
|
||||
|
||||
**优点**:
|
||||
- ApiClient 和 Handler 解耦,避免循环依赖
|
||||
- Handler 通过 self.api_client 访问 HTTP 功能
|
||||
- DataSource 统一管理 ApiClient 生命周期
|
||||
- Handler 内部灵活控制重试策略
|
||||
|
||||
## 10. 关键优势
|
||||
|
||||
1. **简化架构**:去掉 Repository 层,代码量减少 50%
|
||||
2. **职责清晰**:
|
||||
- ApiClient:HTTP 通信
|
||||
- DataSource:协调和轮询
|
||||
- Handler:业务逻辑和重试
|
||||
3. **重试灵活**:Handler 内部实现,不同业务可自定义策略
|
||||
4. **状态清晰**:Load 阶段创建 PENDING 节点,执行阶段明确状态转换
|
||||
5. **批量优化**:Push Log 批量查询,减少 HTTP 请求
|
||||
6. **易于扩展**:新业务只需实现 Handler,复用 Client 和 DataSource
|
||||
7. **易于测试**:ApiClient 可 mock,Handler 独立测试
|
||||
|
||||
## 11. 设计改进总结
|
||||
|
||||
| 改进点 | 初始设计 | 最终设计 | 理由 |
|
||||
|-------|---------|---------|------|
|
||||
| Push Log 查询 | get_push_log(id) | get_push_logs([ids]) | 批量查询 |
|
||||
| 轮询逻辑 | wait_for_push_log 在 Client | 移除,DataSource 调用 poll | 职责清晰 |
|
||||
| created_id 提取 | 在 Client | 在 Handler 基类 | 业务差异 |
|
||||
| 重试逻辑 | 在 DataSource | **在 Handler** | 业务灵活性 |
|
||||
| Load 状态 | GET 成功 → SUCCESS | GET 成功 → PENDING | Load ≠ 同步完成 |
|
||||
| 执行状态 | 不明确 | 执行前设置 IN_PROGRESS | 状态清晰 |
|
||||
7. **易于测试**:ApiClient 可以 mock,Handler 单独测试业务逻辑
|
||||
|
||||
## 12. 使用示例
|
||||
|
||||
### 12.1 基本使用流程
|
||||
|
||||
```python
|
||||
# 1. 创建 DataSource
|
||||
datasource = ApiDataSource(
|
||||
base_url="https://api.example.com",
|
||||
uid="user123",
|
||||
secret="secret_key"
|
||||
)
|
||||
|
||||
# 2. 初始化(必须调用)
|
||||
await datasource.initialize()
|
||||
|
||||
# 3. 注册 Handler
|
||||
datasource.register_handler(ProjectApiHandler())
|
||||
datasource.register_handler(ContractApiHandler())
|
||||
|
||||
# 4. 创建 Collection
|
||||
collection = DataCollection()
|
||||
|
||||
# 5. 加载数据(自动处理异常,不会抛出)
|
||||
await datasource.load_all(collection, order=["project", "contract"])
|
||||
|
||||
# 6. 执行同步(自动处理异常,不会抛出)
|
||||
await datasource.sync_all(collection, order=["project", "contract"])
|
||||
|
||||
# 7. 关闭连接(必须调用)
|
||||
await datasource.close()
|
||||
```
|
||||
|
||||
### 12.2 异常处理说明
|
||||
|
||||
**设计原则**:
|
||||
- ✅ **load_all 和 sync_all 不会抛出异常**
|
||||
- ✅ **Handler 的 create/update/delete 捕获所有 HTTP 异常**
|
||||
- ✅ **所有错误转换为状态(SyncStatus.FAILED)和错误信息(node.error)**
|
||||
|
||||
**为什么不需要 try-finally?**
|
||||
|
||||
```python
|
||||
# ❌ 不需要这样做
|
||||
try:
|
||||
await datasource.load_all(collection, order=["project"])
|
||||
finally:
|
||||
await datasource.close()
|
||||
|
||||
# ✅ 直接调用即可
|
||||
await datasource.initialize()
|
||||
await datasource.load_all(collection, order=["project"]) # 内部已处理异常
|
||||
await datasource.sync_all(collection, order=["project"]) # 内部已处理异常
|
||||
await datasource.close()
|
||||
```
|
||||
|
||||
**异常处理机制**:
|
||||
|
||||
1. **load_all 异常处理**:
|
||||
```python
|
||||
# 加载某个类型失败,记录错误但继续处理其他类型
|
||||
for node_type in order:
|
||||
try:
|
||||
raw_items = await handler.load(collection)
|
||||
# ... 创建节点
|
||||
except Exception as e:
|
||||
print(f"Error loading {node_type}: {e}")
|
||||
# 继续处理下一个类型
|
||||
```
|
||||
|
||||
2. **sync_all 异常处理**:
|
||||
```python
|
||||
# Handler 返回的异常已被捕获转为 TaskResult
|
||||
for node in nodes:
|
||||
try:
|
||||
result = await handler.create(node) # Handler 内部捕获异常
|
||||
# 根据 result.status 更新节点状态
|
||||
except Exception as e:
|
||||
# DataSource 的最后保护
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = str(e)
|
||||
```
|
||||
|
||||
3. **Handler 异常处理**:
|
||||
```python
|
||||
async def create(self, node: SyncNode) -> TaskResult:
|
||||
try:
|
||||
# 生成参数
|
||||
push_id = self._generate_push_id()
|
||||
data = {..., "push_id": push_id, "biz_id": self._generate_biz_id(node)}
|
||||
|
||||
# 调用 API
|
||||
response = await self.api_client.post("/api/v2/project", data)
|
||||
|
||||
# 返回成功
|
||||
return TaskResult(status=TaskStatus.SUCCESS, data_id=response['data']['id'])
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
# HTTP 错误(4xx, 5xx)
|
||||
return TaskResult(status=TaskStatus.FAILED, error=f"HTTP {e.response.status_code}: {e}")
|
||||
except httpx.NetworkError as e:
|
||||
# 网络错误
|
||||
return TaskResult(status=TaskStatus.FAILED, error=f"Network error: {e}")
|
||||
except Exception as e:
|
||||
# 其他异常
|
||||
return TaskResult(status=TaskStatus.FAILED, error=f"Unexpected error: {e}")
|
||||
```
|
||||
|
||||
### 12.3 Pipeline 集成示例
|
||||
|
||||
```python
|
||||
async def sync_pipeline(datasource: ApiDataSource):
|
||||
"""同步流程编排"""
|
||||
|
||||
# 初始化
|
||||
await datasource.initialize()
|
||||
|
||||
# 创建 Collection
|
||||
collection = DataCollection()
|
||||
|
||||
# 执行同步流程(所有错误都被内部处理)
|
||||
await datasource.load_all(collection, order=["project", "contract", "material"])
|
||||
await datasource.sync_all(collection, order=["project", "contract", "material"])
|
||||
|
||||
# 检查结果
|
||||
failed_nodes = collection.filter(status=SyncStatus.FAILED)
|
||||
if failed_nodes:
|
||||
print(f"Failed nodes: {len(failed_nodes)}")
|
||||
for node in failed_nodes:
|
||||
print(f" - {node.node_type}:{node.node_id}: {node.error}")
|
||||
|
||||
# 清理
|
||||
await datasource.close()
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- ✅ 不需要 try-except 包裹 load_all/sync_all
|
||||
- ✅ 通过检查节点状态判断成功/失败
|
||||
- ✅ 错误信息保存在 node.error 中
|
||||
- ✅ Pipeline 专注于流程编排,不处理异常细节
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
# DataSource + Handler 架构设计 V2
|
||||
|
||||
## 核心原则
|
||||
|
||||
### **职责分离**
|
||||
|
||||
```text
|
||||
Strategy (业务逻辑层)
|
||||
↓ 设置 action, 完成 ID 映射
|
||||
DataSource (状态管理 + 编排层)
|
||||
↓ 调用 Handler, 管理状态流转
|
||||
Handler (纯执行层)
|
||||
↓ 调用后端 API, 返回结果
|
||||
Backend API
|
||||
```
|
||||
|
||||
### **关键设计决策**
|
||||
|
||||
1. **ID 映射在 Strategy 完成** ✅
|
||||
- `Strategy.create()` / `Strategy.update()` 时,已将依赖字段的本地 ID 替换为远程 ID
|
||||
- DataSource 拿到的 `node.data` 已经是映射好的数据
|
||||
- Handler 直接使用 `node.data`,不需要关心 ID 映射
|
||||
|
||||
2. **状态管理在 DataSource** ✅
|
||||
- 所有 `node.status` 的转换由 DataSource 负责
|
||||
- Handler 只返回 `TaskResult`(成功/失败/进行中)
|
||||
- DataSource 根据 `TaskResult` 更新 `node.status`
|
||||
|
||||
3. **Handler 只负责执行** ✅
|
||||
- 调用后端 API(load/create/update/delete)
|
||||
- 返回执行结果(TaskResult)
|
||||
- 提供异步任务轮询(poll_tasks)
|
||||
- 提供数据质量检查(validate)
|
||||
|
||||
---
|
||||
|
||||
## Handler 接口设计
|
||||
|
||||
### **核心方法**
|
||||
|
||||
```python
|
||||
class NodeHandler(Protocol[T]):
|
||||
# ===== 数据加载 =====
|
||||
async def load(self, collection: Optional[DataCollection] = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
从后端加载全部数据
|
||||
|
||||
Args:
|
||||
collection: Collection 上下文(可选,用于依赖查询)
|
||||
|
||||
Returns:
|
||||
原始数据列表
|
||||
|
||||
示例:
|
||||
# Contract Handler(依赖 Project)
|
||||
async def load(self, collection=None):
|
||||
# 从 collection 获取 project 列表
|
||||
if collection:
|
||||
projects = collection.filter(node_type="project")
|
||||
project_ids = [p.data_id for p in projects if p.data_id]
|
||||
else:
|
||||
project_ids = []
|
||||
|
||||
# 只加载这些项目的合同
|
||||
response = await self.api.get_contracts(project_ids=project_ids)
|
||||
return response["data"]
|
||||
"""
|
||||
|
||||
# ===== 数据操作 =====
|
||||
async def create(self, node: SyncNode[T]) -> TaskResult:
|
||||
"""
|
||||
创建节点
|
||||
|
||||
注意:node.data 已经过 ID 映射,直接使用即可
|
||||
|
||||
Returns:
|
||||
TaskResult:
|
||||
- SUCCESS: 同步完成,返回 data_id
|
||||
- IN_PROGRESS: 异步任务,返回 task_id
|
||||
- FAILED: 失败,返回 error
|
||||
|
||||
示例:
|
||||
# 同步接口
|
||||
async def create(self, node):
|
||||
try:
|
||||
response = await self.api.create_contract(node.data)
|
||||
return TaskResult.success(data_id=response["id"])
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
|
||||
# 异步接口
|
||||
async def create(self, node):
|
||||
try:
|
||||
response = await self.api.submit_contract_async(node.data)
|
||||
return TaskResult.in_progress(task_id=response["task_id"])
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
"""
|
||||
|
||||
async def update(self, node: SyncNode[T]) -> TaskResult:
|
||||
"""更新节点(同 create)"""
|
||||
|
||||
async def delete(self, node: SyncNode[T]) -> TaskResult:
|
||||
"""删除节点(同 create)"""
|
||||
|
||||
# ===== 异步任务轮询 =====
|
||||
async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
|
||||
"""
|
||||
批量轮询异步任务状态
|
||||
|
||||
Args:
|
||||
task_ids: 任务 ID 列表
|
||||
|
||||
Returns:
|
||||
{task_id: TaskResult} 字典
|
||||
|
||||
示例:
|
||||
async def poll_tasks(self, task_ids):
|
||||
response = await self.api.batch_query_tasks(task_ids)
|
||||
results = {}
|
||||
for task in response["tasks"]:
|
||||
if task["status"] == "completed":
|
||||
results[task["id"]] = TaskResult.success(
|
||||
data_id=task["result"]["contract_id"]
|
||||
)
|
||||
elif task["status"] == "failed":
|
||||
results[task["id"]] = TaskResult.failed(
|
||||
error=task["error"]
|
||||
)
|
||||
else: # running
|
||||
results[task["id"]] = TaskResult.in_progress(
|
||||
task_id=task["id"]
|
||||
)
|
||||
return results
|
||||
"""
|
||||
|
||||
# ===== 数据质量检查 =====
|
||||
async def validate(self, data: Dict[str, Any]) -> ValidationResult:
|
||||
"""
|
||||
数据质量检查
|
||||
|
||||
Args:
|
||||
data: 原始数据
|
||||
|
||||
Returns:
|
||||
ValidationResult(是否有效 + 错误列表)
|
||||
|
||||
示例:
|
||||
async def validate(self, data):
|
||||
errors = []
|
||||
if not data.get("code"):
|
||||
errors.append("合同编码为空")
|
||||
if not data.get("project_id"):
|
||||
errors.append("项目 ID 为空")
|
||||
|
||||
return ValidationResult(
|
||||
is_valid=len(errors) == 0,
|
||||
errors=errors
|
||||
)
|
||||
"""
|
||||
|
||||
# ===== 辅助方法 =====
|
||||
def extract_id(self, data: Dict[str, Any]) -> str:
|
||||
"""从原始数据提取 ID"""
|
||||
|
||||
def create_node(self, data: Dict[str, Any]) -> SyncNode[T]:
|
||||
"""从原始数据创建 SyncNode"""
|
||||
```
|
||||
|
||||
### **TaskResult 设计**
|
||||
|
||||
```python
|
||||
class TaskStatus(Enum):
|
||||
SUCCESS = "success" # 同步完成
|
||||
FAILED = "failed" # 失败
|
||||
IN_PROGRESS = "in_progress" # 异步任务进行中
|
||||
|
||||
|
||||
class TaskResult:
|
||||
def __init__(
|
||||
self,
|
||||
status: TaskStatus,
|
||||
data_id: Optional[str] = None, # 成功时返回的 ID
|
||||
task_id: Optional[str] = None, # 异步任务 ID
|
||||
error: Optional[str] = None, # 失败原因
|
||||
metadata: Optional[Dict] = None # 其他元数据
|
||||
):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def success(cls, data_id: Optional[str] = None) -> TaskResult:
|
||||
"""创建成功结果"""
|
||||
|
||||
@classmethod
|
||||
def failed(cls, error: str) -> TaskResult:
|
||||
"""创建失败结果"""
|
||||
|
||||
@classmethod
|
||||
def in_progress(cls, task_id: str) -> TaskResult:
|
||||
"""创建进行中结果"""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DataSource 接口设计
|
||||
|
||||
### **接口方法**
|
||||
|
||||
```python
|
||||
class BaseDataSource(ABC):
|
||||
# ===== Handler 管理 =====
|
||||
def register_handler(self, handler: NodeHandler) -> None:
|
||||
"""注册 Handler"""
|
||||
|
||||
def get_handler(self, node_type: str) -> NodeHandler:
|
||||
"""获取 Handler"""
|
||||
|
||||
# ===== 数据加载 =====
|
||||
async def load_all(
|
||||
self,
|
||||
order: List[str]
|
||||
) -> None:
|
||||
"""
|
||||
按依赖顺序加载所有数据
|
||||
|
||||
注意:调用前需先 set_collection()
|
||||
|
||||
Args:
|
||||
order: 节点类型顺序(如 ["project", "contract", "construction"])
|
||||
|
||||
工作流程:
|
||||
1. 按顺序遍历每个节点类型
|
||||
2. 调用 Handler.load()
|
||||
3. Handler 可以从 self._collection 查询依赖节点
|
||||
4. 使用 Handler.create_node() 创建 SyncNode
|
||||
5. 添加到 Collection
|
||||
"""
|
||||
|
||||
# ===== 同步执行 =====
|
||||
async def sync_all(
|
||||
self,
|
||||
order: List[str]
|
||||
) -> None:
|
||||
"""
|
||||
按依赖顺序执行同步
|
||||
|
||||
流程:
|
||||
1. 按顺序遍历每个节点类型
|
||||
2. 筛选需要同步的节点(status=PENDING, action!=NONE)
|
||||
3. 调用 Handler 的 create/update/delete
|
||||
4. 根据 TaskResult 更新节点状态
|
||||
5. 处理异步任务轮询
|
||||
"""
|
||||
|
||||
# ===== 统计信息 =====
|
||||
def get_sync_summary(self, collection: DataCollection) -> Dict[str, Any]:
|
||||
"""获取同步统计信息"""
|
||||
```
|
||||
|
||||
### **状态流转逻辑**
|
||||
|
||||
```python
|
||||
async def _sync_nodes(self, handler, nodes):
|
||||
async_tasks = {} # {node_id: task_id}
|
||||
|
||||
for node in nodes:
|
||||
# 1. 跳过不需要处理的节点
|
||||
if node.action == SyncAction.NONE:
|
||||
continue
|
||||
|
||||
# 2. 跳过异常状态节点
|
||||
if node.binding_status in [DEPENDENCY_ERROR, ABNORMAL, WARNING]:
|
||||
node.status = SyncStatus.SKIPPED
|
||||
continue
|
||||
|
||||
# 3. 只处理 PENDING 节点
|
||||
if node.status != SyncStatus.PENDING:
|
||||
continue
|
||||
|
||||
# 4. 执行操作
|
||||
try:
|
||||
node.status = SyncStatus.IN_PROGRESS
|
||||
|
||||
if node.action == SyncAction.CREATE:
|
||||
result = await handler.create(node)
|
||||
elif node.action == SyncAction.UPDATE:
|
||||
result = await handler.update(node)
|
||||
elif node.action == SyncAction.DELETE:
|
||||
result = await handler.delete(node)
|
||||
|
||||
# 5. 处理结果
|
||||
if result.status == TaskStatus.SUCCESS:
|
||||
node.status = SyncStatus.SUCCESS
|
||||
if result.data_id:
|
||||
node.data_id = result.data_id # 回填 ID
|
||||
|
||||
elif result.status == TaskStatus.FAILED:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = result.error
|
||||
|
||||
elif result.status == TaskStatus.IN_PROGRESS:
|
||||
async_tasks[node.node_id] = result.task_id
|
||||
|
||||
except Exception as e:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = str(e)
|
||||
|
||||
# 6. 轮询异步任务
|
||||
if async_tasks:
|
||||
await self._poll_async_tasks(handler, nodes, async_tasks)
|
||||
```
|
||||
|
||||
### **异步任务轮询**
|
||||
|
||||
```python
|
||||
async def _poll_async_tasks(self, handler, nodes, async_tasks):
|
||||
node_map = {n.node_id: n for n in nodes}
|
||||
|
||||
max_retries = poll_max_retries # 默认轮询 1 次,可配置
|
||||
retry_count = 0
|
||||
|
||||
while async_tasks and retry_count < max_retries:
|
||||
# 批量查询
|
||||
task_ids = list(async_tasks.values())
|
||||
results = await handler.poll_tasks(task_ids)
|
||||
|
||||
# 处理结果
|
||||
for node_id, task_id in list(async_tasks.items()):
|
||||
if task_id not in results:
|
||||
continue
|
||||
|
||||
result = results[task_id]
|
||||
node = node_map[node_id]
|
||||
|
||||
if result.status == TaskStatus.SUCCESS:
|
||||
node.status = SyncStatus.SUCCESS
|
||||
if result.data_id:
|
||||
node.data_id = result.data_id
|
||||
async_tasks.pop(node_id)
|
||||
|
||||
elif result.status == TaskStatus.FAILED:
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = result.error
|
||||
async_tasks.pop(node_id)
|
||||
|
||||
# 还有未完成任务,等待后重试
|
||||
if async_tasks:
|
||||
await asyncio.sleep(2)
|
||||
retry_count += 1
|
||||
|
||||
# 超时未完成的任务标记为失败
|
||||
for node_id in async_tasks:
|
||||
node = node_map[node_id]
|
||||
node.status = SyncStatus.FAILED
|
||||
node.error = "Async task timeout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整流程示例
|
||||
|
||||
### **Pipeline 编排**
|
||||
|
||||
```python
|
||||
# Stage 0: 初始化
|
||||
collection = DataCollection()
|
||||
datasource = ApiDataSource(api_client)
|
||||
|
||||
# 注册 Handler
|
||||
datasource.register_handler(ProjectNodeHandler(api_client))
|
||||
datasource.register_handler(ContractNodeHandler(api_client))
|
||||
|
||||
# Stage 1: 加载数据
|
||||
datasource.set_collection(collection)
|
||||
await datasource.load_all(
|
||||
order=["project", "contract"] # 依赖顺序
|
||||
)
|
||||
|
||||
# Stage 2: Strategy 执行
|
||||
for strategy in [project_strategy, contract_strategy]:
|
||||
await strategy.bind() # 设置 binding_status
|
||||
await strategy.create() # 设置 action=CREATE + ID 映射
|
||||
await strategy.update() # 设置 action=UPDATE + ID 映射
|
||||
await strategy.pre_sync_check()
|
||||
|
||||
# Stage 3: 物理同步
|
||||
await datasource.sync_all(
|
||||
order=["project", "contract"]
|
||||
)
|
||||
|
||||
# Stage 4: 检查结果
|
||||
summary = datasource.get_sync_summary(collection)
|
||||
print(f"Success: {summary['success']}, Failed: {summary['failed']}")
|
||||
```
|
||||
|
||||
### **Contract Handler 实现**
|
||||
|
||||
```python
|
||||
class ContractNodeHandler(BaseNodeHandler[ContractResponse]):
|
||||
def __init__(self, api_client):
|
||||
super().__init__(
|
||||
node_type="contract",
|
||||
node_class=ContractSyncNode,
|
||||
schema=ContractResponse
|
||||
)
|
||||
self.api = api_client
|
||||
|
||||
async def load(self):
|
||||
"""加载合同(依赖 Project)"""
|
||||
if self._collection:
|
||||
projects = self._collection.filter(node_type="project")
|
||||
project_ids = [p.data_id for p in projects if p.data_id]
|
||||
else:
|
||||
project_ids = []
|
||||
|
||||
response = await self.api.get_contracts(project_ids=project_ids)
|
||||
return response["data"]
|
||||
|
||||
async def create(self, node):
|
||||
"""创建合同(异步接口)"""
|
||||
try:
|
||||
# node.data 已经过 ID 映射,直接使用
|
||||
response = await self.api.create_contract_async(node.data)
|
||||
|
||||
if response.get("async"):
|
||||
return TaskResult.in_progress(task_id=response["task_id"])
|
||||
else:
|
||||
return TaskResult.success(data_id=response["id"])
|
||||
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
|
||||
async def update(self, node):
|
||||
"""更新合同(同步接口)"""
|
||||
try:
|
||||
response = await self.api.update_contract(node.data_id, node.data)
|
||||
return TaskResult.success()
|
||||
except Exception as e:
|
||||
return TaskResult.failed(error=str(e))
|
||||
|
||||
async def poll_tasks(self, task_ids):
|
||||
"""轮询异步任务"""
|
||||
response = await self.api.batch_query_tasks(task_ids)
|
||||
results = {}
|
||||
for task in response["tasks"]:
|
||||
if task["status"] == "completed":
|
||||
results[task["id"]] = TaskResult.success(
|
||||
data_id=task["result"]["contract_id"]
|
||||
)
|
||||
elif task["status"] == "failed":
|
||||
results[task["id"]] = TaskResult.failed(error=task["error"])
|
||||
else:
|
||||
results[task["id"]] = TaskResult.in_progress(task_id=task["id"])
|
||||
return results
|
||||
|
||||
async def validate(self, data):
|
||||
"""数据质量检查"""
|
||||
errors = []
|
||||
if not data.get("code"):
|
||||
errors.append("合同编码为空")
|
||||
if not data.get("project_id"):
|
||||
errors.append("项目 ID 为空")
|
||||
|
||||
return ValidationResult(is_valid=len(errors) == 0, errors=errors)
|
||||
|
||||
def extract_id(self, data):
|
||||
return data["id"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心优势
|
||||
|
||||
### **1. 职责清晰**
|
||||
|
||||
- **Strategy**: 业务逻辑 + ID 映射
|
||||
- **DataSource**: 状态管理 + 编排
|
||||
- **Handler**: 纯执行(后端 API 调用)
|
||||
|
||||
### **2. ID 映射前置**
|
||||
|
||||
- ID 映射在 Strategy 完成,DataSource 和 Handler 无需关心
|
||||
- `node.data` 已经是映射好的数据,直接使用
|
||||
|
||||
### **3. 状态统一管理**
|
||||
|
||||
- 所有状态流转由 DataSource 负责
|
||||
- Handler 只返回结果,不改变节点状态
|
||||
|
||||
### **4. 异步任务支持**
|
||||
|
||||
- Handler 返回 `TaskResult.in_progress(task_id)`
|
||||
- DataSource 自动轮询直到完成
|
||||
|
||||
### **5. 数据质量保障**
|
||||
|
||||
|
||||
- Handler 提供 `validate()` 方法
|
||||
- DataSource 在加载时检查数据质量
|
||||
|
||||
### **6. 易于测试**
|
||||
|
||||
- Handler 可以 Mock(返回假 TaskResult)
|
||||
- DataSource 可以单独测试状态流转逻辑
|
||||
- Strategy 可以单独测试 ID 映射逻辑
|
||||
|
||||
---
|
||||
|
||||
## 与现有架构的兼容性
|
||||
|
||||
完全符合 [架构分层设计.md](./架构分层设计.md) 的四层模型:
|
||||
|
||||
1. **Common 层**: SyncNode, DataCollection, BindingManager
|
||||
2. **Sync System 层**: SyncStrategy(负责 bind/create/update + ID 映射)
|
||||
3. **DataSource 层**: BaseDataSource + NodeHandler(状态管理 + 执行)
|
||||
4. **Pipeline 层**: 流程编排 + 依赖顺序
|
||||
|
||||
符合 [状态定义规范.md](./状态定义规范.md) 的状态流转逻辑。
|
||||
@@ -0,0 +1,150 @@
|
||||
# node_id / data_id / 持久化与生命周期说明
|
||||
|
||||
本文档说明同步系统中 `node_id` 与 `data_id` 的职责、生成时机、持久化行为,以及同步流程中“创建/绑定/回填”的完整生命周期。目标是避免“重复生成 node_id 导致绑定失效”的问题,并明确各层职责。
|
||||
|
||||
---
|
||||
|
||||
## 1. 基础概念
|
||||
|
||||
- **data_id**
|
||||
- 业务主键(来自数据源/远端系统的资源 ID)。
|
||||
- 在加载阶段通常已存在;在 CREATE 场景下初始为空,成功后由 DataSource 回填。
|
||||
|
||||
- **node_id**
|
||||
- 同步系统内部的**稳定标识符**(绑定与持久化的主键)。
|
||||
- 用于绑定表、持久化节点、依赖追踪等。
|
||||
- 设计目标:**跨同步周期稳定**,不能随每次加载而变化。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心结论(必须遵守)
|
||||
|
||||
1. **node_id 一旦建立,不应再被数据源“重新生成”。**
|
||||
- 绑定关系与持久化状态依赖 `node_id`;若每次加载都重新生成,会导致历史绑定失效。
|
||||
2. **加载阶段应先恢复 Collection(持久化节点),再加载 DataSource 数据。**
|
||||
- 数据源加载出的 `data_id` 应优先匹配已持久化的节点;匹配到则复用旧 `node_id`。
|
||||
3. **CREATE 场景允许临时/新建 node_id**,但必须通过后续回填与绑定更新保持一致性。
|
||||
|
||||
---
|
||||
|
||||
## 3. 正确的初始化/加载顺序
|
||||
|
||||
### 推荐流程(Pipeline 前半段)
|
||||
|
||||
1. **持久化恢复阶段**
|
||||
- 必须同时恢复 `node_id` 与 `data_id`(以及状态字段),否则无法建立稳定的映射关系。
|
||||
- Collection 可能为空,这属于合法情况。
|
||||
|
||||
2. **数据源加载阶段(DataSource.load_all)**
|
||||
- 对每一条业务数据(含 `data_id`):
|
||||
- **若 Collection 内已存在该 `data_id` 对应节点**:将数据写回原节点(保留旧 `node_id`)。
|
||||
- **若不存在**:由 **Collection** 生成新的 `node_id`,并创建新节点。
|
||||
|
||||
> 这样可避免“第二次同步时重建节点,导致旧绑定丢失”。
|
||||
|
||||
---
|
||||
|
||||
## 4. node_id 的来源与稳定性
|
||||
|
||||
### A. 持久化恢复阶段
|
||||
|
||||
- **恢复时必须包含 `node_id` 与 `data_id`**:
|
||||
- 两者成对恢复,才能保证后续 load 阶段按 `data_id` 命中旧节点。
|
||||
|
||||
### B. 数据源加载阶段
|
||||
|
||||
- **优先复用持久化 node_id**:
|
||||
- 通过 `data_id` 在 Collection 中查找并更新已有节点。
|
||||
- **仅在未知 data_id 时新建 node_id**:
|
||||
- 新节点 `node_id` 必须由 **Collection** 生成,而非 DataSource/Handler 直接拼接。
|
||||
|
||||
### C. 创建阶段(Strategy.create)
|
||||
|
||||
- 新建“目标端”节点时,**必须有 node_id**:
|
||||
- 用于写入 Collection、记录状态、建立临时绑定。
|
||||
- 成功后回填 `data_id`,**node_id 不变**。
|
||||
|
||||
---
|
||||
|
||||
## 5. data_id 的来源与回填
|
||||
|
||||
本节按阶段拆分说明 `data_id` 的来源与写回。
|
||||
|
||||
### A. 持久化恢复阶段
|
||||
|
||||
- `data_id` 从持久化数据中恢复(与 `node_id` 一起恢复)。
|
||||
|
||||
### B. 数据源加载阶段
|
||||
|
||||
- `data_id` 来自数据源原始数据(`id` / `_id`)。
|
||||
- 若命中已有节点,则仅更新数据与状态,不改变 `node_id`。
|
||||
|
||||
### C. 同步创建与轮询阶段
|
||||
|
||||
- CREATE 提交后,DataSource 从响应/轮询结果提取 `biz_id`。
|
||||
- 成功时回填到 `node.data_id`,并回写 `node.data` 的主键字段(仅 `id` / `_id`)。
|
||||
|
||||
### D. 持久化阶段
|
||||
|
||||
- 将更新后的 `node_id` / `data_id` / 状态字段持久化,供下次同步恢复使用。
|
||||
|
||||
---
|
||||
|
||||
## 6. 绑定与 node_id 的关系
|
||||
|
||||
- 绑定表的 key 为 `node_id`,绑定记录是 `local_node_id <-> remote_node_id`。
|
||||
- 因此:**node_id 必须稳定**,才能保证绑定长期有效。
|
||||
- 绑定可在创建前建立“临时关系”,但成功后不应更换 node_id。
|
||||
|
||||
---
|
||||
|
||||
## 7. 同步周期中的典型场景
|
||||
|
||||
### 场景 1:第一次同步(无持久化)
|
||||
- Collection 为空 → DataSource load 新节点 → 生成新 `node_id`。
|
||||
- Strategy bind / create / update 执行。
|
||||
- 持久化后,下次同步可复用 `node_id`。
|
||||
|
||||
### 场景 2:第二次同步(已有持久化)
|
||||
- 先恢复 Collection(已有 `node_id`)。
|
||||
- DataSource load 时按 `data_id` 匹配旧节点并更新数据。
|
||||
- 绑定关系仍有效。
|
||||
|
||||
### 场景 3:创建新数据(CREATE)
|
||||
- Strategy 产生目标端节点(`node_id` 新生成)。
|
||||
- DataSource 执行创建,回填 `data_id`。
|
||||
- 绑定记录更新为真实 `data_id`(但 node_id 保持不变)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 关键规则总结
|
||||
|
||||
- **node_id 是“同步系统内的稳定 ID”,必须持久化与复用。**
|
||||
- **data_id 是“业务系统的资源 ID”,由数据源加载或创建后回填。**
|
||||
- **加载顺序:先恢复持久化节点 → 再 load 数据源。**
|
||||
- **遇到已存在 data_id:复用 node_id;否则创建新节点。**
|
||||
- **CREATE 成功后只更新 data_id,不更换 node_id。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 相关文件参考
|
||||
|
||||
- 绑定与状态定义:见 [docs/状态定义规范.md](状态定义规范.md)
|
||||
- 编排流程:见 [docs/编排流程规范.md](编排流程规范.md)
|
||||
- BaseDataSource:见 [sync_system_new/datasource/datasource.py](../sync_system_new/datasource/datasource.py)
|
||||
- BaseApiHandler:见 [sync_system_new/datasource/api/handler.py](../sync_system_new/datasource/api/handler.py)
|
||||
|
||||
---
|
||||
|
||||
## 10. 明确规则与建议实现
|
||||
|
||||
- **DataSource.load_all 必须先按 `data_id` 命中已有节点并更新**,未命中时再由 Collection 创建新节点并分配新的 `node_id`。
|
||||
- **推荐实现方式**:先 `find_by_data_id`,命中走通用更新;未命中再创建新节点(无需强制 `upsert_by_data_id` 接口)。
|
||||
- **创建流程中的临时绑定/成功更新规则**:
|
||||
- CREATE 节点创建时:`binding_status = NORMAL`,`action = CREATE`,`status = PENDING`,`data_id = ""`。
|
||||
- 执行提交前置为 `status = IN_PROGRESS`(异步)或保持 `PENDING`(同步接口待执行)。
|
||||
- 成功回填后:`status = SUCCESS`,`data_id` 回填并写回主键字段,绑定记录保持 `node_id` 不变。
|
||||
- 过程中出现错误:`status = FAILED`,`error` 记录原因。
|
||||
- **异常节点持久化/恢复策略**:
|
||||
- 持久化时保留异常节点与错误信息。
|
||||
- 恢复时是否保留/清理异常节点应通过策略配置控制(默认建议保留以便人工修复)。
|
||||
@@ -0,0 +1,232 @@
|
||||
# Skip Sync 行为修复说明
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 1. **绑定失败的根本原因**
|
||||
|
||||
**问题现象**:
|
||||
- Company: 1/39 绑定
|
||||
- Supplier: 0/65202 绑定(完全没绑定!)
|
||||
- 导致依赖supplier的业务(contract, material等)也绑不上
|
||||
- 远程异常创建了74条数据
|
||||
|
||||
**根本原因有两个**:
|
||||
|
||||
#### 原因1:skip_sync 跳过了整个策略(包括 bind)
|
||||
|
||||
```python
|
||||
# 旧逻辑:skip_sync=True 时跳过整个策略
|
||||
if getattr(strategy, 'skip_sync', False):
|
||||
continue # ← 跳过了 bind/create/update 全部!
|
||||
```
|
||||
|
||||
修复后:
|
||||
```python
|
||||
# 新逻辑:bind() 始终执行,skip_sync 只跳过 create/update/sync
|
||||
await strategy.bind() # ← 始终执行
|
||||
|
||||
if getattr(strategy, 'skip_sync', False):
|
||||
continue # ← 只跳过 create/update
|
||||
```
|
||||
|
||||
#### 原因2:自动绑定ID解析失败没有设置DEPENDENCY_ERROR
|
||||
|
||||
```python
|
||||
# 旧逻辑:ID解析失败只是跳过
|
||||
if not resolved_key_dict:
|
||||
continue # ← 节点保持 MISSING,会被误创建!
|
||||
```
|
||||
|
||||
修复后:
|
||||
```python
|
||||
# 新逻辑:ID解析失败设置DEPENDENCY_ERROR
|
||||
if not resolved_key_dict:
|
||||
node.set_binding_status(BindingStatus.DEPENDENCY_ERROR, "业务键中的ID字段解析失败")
|
||||
continue # ← 节点为 DEPENDENCY_ERROR,不会被创建
|
||||
```
|
||||
|
||||
### 2. **状态与创建的关系**
|
||||
|
||||
| 状态 | 来源 | 允许创建 | 说明 |
|
||||
|------|------|:---:|------|
|
||||
| **UNCHECKED** | 加载后初始状态 | ❌ | bind() 未执行 |
|
||||
| **NORMAL** | 有绑定记录 | ❌ | 已绑定 |
|
||||
| **MISSING** | 无绑定记录 | ✅ | 真正的孤儿 |
|
||||
| **WARNING** | 业务键字段缺失 | ❌ | 数据不完整 |
|
||||
| **DEPENDENCY_ERROR** | 依赖不满足 | ❌ | 父节点未就绪 |
|
||||
| **ABNORMAL** | 数据损坏 | ❌ | 需人工处理 |
|
||||
|
||||
**关键原则**:
|
||||
- `create()` 只查找 `binding_status == MISSING` 的节点
|
||||
- 如果 bind() 没执行,状态是 UNCHECKED → 不会创建
|
||||
- 如果 bind() 执行了但依赖不满足 → DEPENDENCY_ERROR → 不会创建
|
||||
|
||||
### 3. **Supplier 默认行为变更**
|
||||
|
||||
**旧行为**:
|
||||
- `default_skip_sync = True` → 默认跳过同步
|
||||
- 需要在调用层设置 `force_sync_types=["supplier"]`
|
||||
|
||||
**新行为**:
|
||||
- `default_skip_sync` 已移除(使用基类默认值 False)
|
||||
- Supplier 默认会执行完整同步(bind/create/update)
|
||||
- 如需跳过,在调用层配置 `skip_sync_types=["supplier"]`
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 修改 1:分离 bind() 和 skip_sync
|
||||
|
||||
**新逻辑**:
|
||||
```python
|
||||
# sync_system_new/pipeline/full_sync_pipeline.py
|
||||
|
||||
# Step 1a: 绑定(始终执行)
|
||||
await strategy.bind()
|
||||
|
||||
# Step 1b: 检查是否跳过 create/update/sync
|
||||
if getattr(strategy, 'skip_sync', False):
|
||||
print(f"⏭️ Skipping create/update/sync for {node_type}")
|
||||
# 继续执行 pre_sync_check,但跳过 create/update/sync
|
||||
if hasattr(strategy, "pre_sync_check"):
|
||||
ok = await strategy.pre_sync_check()
|
||||
...
|
||||
continue
|
||||
|
||||
# Step 1c: 正常的 create/update
|
||||
await strategy.create()
|
||||
await strategy.update()
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- ✅ **bind() 始终执行**(建立绑定关系)
|
||||
- ✅ **skip_sync=True 只跳过 create/update/sync**(避免昂贵操作)
|
||||
- ✅ **pre_sync_check 仍然执行**(依赖检查)
|
||||
|
||||
### 修改 2:添加 force_sync_types 配置
|
||||
|
||||
**配置示例**:
|
||||
```python
|
||||
# tests/run_full_sync_pipeline_simple.py
|
||||
CONFIG = {
|
||||
# 第一次运行:从 API 加载 + 绑定 + 创建
|
||||
"force_sync_types": ["supplier"],
|
||||
"wipe_persistence_on_start": True,
|
||||
|
||||
# 第二次运行:从持久化加载 + 跳过同步
|
||||
# "handler_configs": {"supplier": {"load_mode": "persisted_only"}},
|
||||
# "skip_sync_types": ["supplier"],
|
||||
# "wipe_persistence_on_start": False,
|
||||
}
|
||||
```
|
||||
|
||||
**优先级**:
|
||||
1. **force_sync_types**(最高)→ `skip_sync = False`
|
||||
2. **skip_sync_types** → `skip_sync = True`
|
||||
3. **策略默认值** (default_skip_sync)
|
||||
|
||||
### 修改 3:添加测试日志保存
|
||||
|
||||
**功能**:
|
||||
```python
|
||||
# tests/run_full_sync_pipeline_simple.py
|
||||
log_path = log_dir / f"simple_pipeline_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
||||
sys.stdout = Tee(original_stdout, log_file)
|
||||
```
|
||||
|
||||
**输出位置**:
|
||||
```
|
||||
test_results/simple_pipeline_20260204_162345.log
|
||||
```
|
||||
|
||||
## 使用指南
|
||||
|
||||
### Phase 1: 首次运行(API + 绑定 + 创建)
|
||||
|
||||
```python
|
||||
CONFIG = {
|
||||
# 不需要特殊配置,所有类型默认都会同步
|
||||
"wipe_persistence_on_start": True, # 清空数据库
|
||||
}
|
||||
```
|
||||
|
||||
**预期结果**:
|
||||
- Supplier: 从API加载60000条 → 自动绑定(credit_code) → 拉取到本地 → 持久化
|
||||
- Company: 自动绑定 → 拉取
|
||||
- Contract等: 通过supplier_id/project_id绑定 → 创建
|
||||
|
||||
### Phase 2: 后续运行(持久化 + 跳过同步)
|
||||
|
||||
```python
|
||||
CONFIG = {
|
||||
"handler_configs": {
|
||||
"supplier": {"load_mode": "persisted_only"} # 从DB加载
|
||||
},
|
||||
"skip_sync_types": ["supplier"], # 跳过create/update(但仍执行bind)
|
||||
"wipe_persistence_on_start": False, # 保留数据
|
||||
}
|
||||
```
|
||||
|
||||
**预期结果**:
|
||||
- Supplier: 从DB加载(带绑定关系) → 执行bind(验证状态) → 跳过create/update
|
||||
- 其他业务: 正常同步
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 1. 删除远程异常创建的数据
|
||||
|
||||
```bash
|
||||
# TODO: 通过API删除远程的74条测试数据
|
||||
```
|
||||
|
||||
### 2. 清空数据库重新测试
|
||||
|
||||
```bash
|
||||
rm _runtime/test_simple.db
|
||||
python scripts/legacy/run_full_sync_pipeline_simple.py
|
||||
```
|
||||
|
||||
### 3. 验证绑定统计
|
||||
|
||||
**期望输出**:
|
||||
```
|
||||
Local Summary:
|
||||
company: 39/39 bindings ← 全部绑定
|
||||
supplier: 60000+/65202 bindings ← 大量绑定
|
||||
contract: XX/34 bindings ← 通过supplier_id绑定
|
||||
|
||||
Remote Summary:
|
||||
company: 39/39 bindings
|
||||
supplier: 60000+/60000 bindings
|
||||
contract: XX/155 bindings (XX creates)
|
||||
```
|
||||
|
||||
### 4. 检查日志文件
|
||||
|
||||
```bash
|
||||
cat test_results/simple_pipeline_*.log | grep "Skipping"
|
||||
```
|
||||
|
||||
**期望**:
|
||||
- 第一次运行:**不应该有** "Skipping" 输出
|
||||
- 第二次运行:`⏭️ Skipping create/update/sync for supplier`
|
||||
|
||||
## 风险评估
|
||||
|
||||
### 影响范围
|
||||
- ✅ 修复了 supplier/company 绑定失败问题
|
||||
- ✅ 防止未绑定节点异常创建
|
||||
- ✅ 保持了两阶段工作流(首次API+绑定,后续持久化)
|
||||
- ⚠️ 可能影响其他使用 skip_sync 的场景(需要测试)
|
||||
|
||||
### 向后兼容性
|
||||
- ✅ 原始脚本 (run_full_sync_pipeline_api.py) 不受影响
|
||||
- ✅ 没有 skip_sync 属性的策略行为不变
|
||||
- ✅ 新增的 force_sync_types 是可选参数
|
||||
|
||||
## 待办事项
|
||||
|
||||
- [ ] 测试所有业务类型的绑定统计
|
||||
- [ ] 验证依赖关系链(project → contract → material → detail)
|
||||
- [ ] 检查 construction_task 为什么没绑定(0/32)
|
||||
- [ ] 测试第二次运行的持久化加载逻辑
|
||||
- [ ] 更新文档说明 skip_sync 的新语义
|
||||
@@ -0,0 +1,72 @@
|
||||
# 业务流程与依赖关系
|
||||
|
||||
本文档描述推送系统涉及的业务实体及其依赖关系,用于指导同步顺序编排。
|
||||
|
||||
---
|
||||
|
||||
## 业务实体分类
|
||||
|
||||
### 1. 基础数据(仅拉取)
|
||||
|
||||
- **用户(User)**:拉取集团管理员、区域公司管理员及特定用户信息,用于跨平台穿透。其他用户需手动创建。
|
||||
- **公司(Company)**:仅拉取,不推送。
|
||||
- **供应商(Supplier)**:仅拉取,不推送。
|
||||
|
||||
### 2. 项目及扩展数据
|
||||
|
||||
**项目(Project)**
|
||||
- **绑定方式**:必须手动绑定(根节点)
|
||||
- **同步操作**:允许更新和拉取
|
||||
- **依赖项**:公司、附件(Attachment)
|
||||
|
||||
**项目扩展业务**
|
||||
- 通过 `(project_id, key)` 或 `(project_id, code)` 自动绑定
|
||||
- 允许创建、更新、拉取
|
||||
- 依赖项目
|
||||
|
||||
### 3. 合同及子业务
|
||||
|
||||
**合同(Contract)**
|
||||
- **绑定方式**:通过业务键自动绑定(需与 ECP 平台数据交叉检验)
|
||||
- **同步操作**:允许拉取、创建、更新、删除
|
||||
- **依赖项**:项目
|
||||
|
||||
**合同子业务**(施工任务、物资、结算、力能)
|
||||
- **绑定方式**:通过 `(contract_id, code)` 自动绑定
|
||||
- **同步操作**:允许拉取、创建、更新、删除
|
||||
- **特殊规则**:首次绑定后,项目侧不会同步创建远程已有的数据
|
||||
- **依赖项**:合同
|
||||
|
||||
**合同子业务明细**(施工明细、物资明细、结算明细、力能明细)
|
||||
- **绑定方式**:通过 `(parent_id, date)` 自动绑定
|
||||
- **同步操作**:允许拉取、创建、更新、删除
|
||||
- **特殊规则**:首次绑定后,项目侧不会同步创建远程已有的数据
|
||||
- **依赖项**:对应的合同子业务
|
||||
|
||||
---
|
||||
|
||||
## 依赖关系图
|
||||
|
||||
```
|
||||
Company (基础)
|
||||
↓
|
||||
Project (手动绑定)
|
||||
↓
|
||||
Contract (自动绑定)
|
||||
↓
|
||||
Contract Sub-Business (施工/物资/结算/力能)
|
||||
↓
|
||||
Details (明细)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 同步顺序原则
|
||||
|
||||
1. **依赖优先**:父节点必须先于子节点同步
|
||||
2. **绑定传递**:子节点的业务键构建依赖父节点的 ID 映射
|
||||
3. **故障隔离**:父节点同步失败时,子节点标记为 `DEPENDENCY_ERROR` 并跳过
|
||||
|
||||
详细状态定义参见:[sync_system_new/sync_system/STATE_DEFINITIONS.md](../sync_system_new/sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
详细架构设计参见:[sync_system_new/architecture_layers.md](../sync_system_new/architecture_layers.md)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
# 节点状态持久化与人工介入规范
|
||||
|
||||
> **代码实现**:`sync_system_new/common/state_reset.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. 持久化规则
|
||||
|
||||
### 1.1 持久化目标
|
||||
|
||||
| 目标 | 说明 |
|
||||
|------|------|
|
||||
| **可恢复性** | 系统重启后能从上次状态继续 |
|
||||
| **可观测性** | 失败和异常状态要保留,供人工查看 |
|
||||
| **可追溯性** | 失败信息持久化,不自动重试,需人工确认 |
|
||||
| **绑定稳定性** | 手工绑定一旦建立,永不自动改变 |
|
||||
|
||||
### 1.2 分阶段重置设计
|
||||
|
||||
状态重置分为两个阶段执行:
|
||||
|
||||
#### 阶段1:加载时重置(Collection.load_from_persistence)
|
||||
|
||||
| 字段 | 性质 | 持久化 | 阶段1重置 |
|
||||
|------|------|--------|-----------|
|
||||
| `node_id` | 恒定标识 | ✅ 必须 | ❌ 不重置 |
|
||||
| `data_id` | 业务主键 | ✅ 必须 | ❌ 不重置 |
|
||||
| `data` | 业务数据 | ✅ 必须 | ✅ **重置**(每次重新取数) |
|
||||
| `origin_data` | 原始快照 | ✅ 必须 | ✅ **重置**(每次重新取数) |
|
||||
| `depend_ids` | 依赖列表 | ❌ **不持久化** | ✅ **初始化为[]**(bind 阶段从 data 实时计算) |
|
||||
| `binding_status` | 绑定状态 | ✅ 必须 | ✅ **重置为 UNCHECKED** |
|
||||
| `action` | 同步意图 | ✅ 保存 | ❌ **保留**(用于阶段2判断) |
|
||||
| `status` | 执行状态 | ✅ 保存 | ❌ **保留**(全部保留,不重置) |
|
||||
| `error` | 错误信息 | ✅ 保存 | ✅ **重置为None**(清空上次错误) |
|
||||
| `context` | 扩展上下文 | ✅ 保存 | ❌ 不重置 |
|
||||
|
||||
#### 阶段2:数据加载后清理(Pipeline._cleanup_create_failed_zombies)
|
||||
|
||||
在数据加载完成后、策略执行前,执行CREATE失败节点清理:
|
||||
|
||||
1. **检查条件**:
|
||||
- 本地节点 `action == CREATE`(上次尝试创建)
|
||||
- 本地节点 `status == FAILED`(创建失败)
|
||||
|
||||
2. **清理动作**:
|
||||
- **删除本地失败节点**(从 collection 中移除)
|
||||
- 如果有绑定记录:
|
||||
- 解除绑定关系
|
||||
- 删除远程 collection 中的僵尸节点
|
||||
|
||||
3. **最后重置 action**:
|
||||
- 所有剩余节点的 `action` 重置为 NONE
|
||||
- 准备进入策略阶段
|
||||
|
||||
4. **下次同步的自动恢复**:
|
||||
- 被删除的节点会从数据源重新加载
|
||||
- 如果远程实际已创建成功(网络波动导致未获取到结果)→ 绑定阶段会自动绑定上
|
||||
- 如果远程实际也失败了 → 重新尝试创建
|
||||
|
||||
5. **UPDATE 阶段保护**:
|
||||
- UPDATE 操作会跳过所有 `status == FAILED` 的节点
|
||||
- 防止 UPDATE 阶段覆盖 CREATE/UPDATE 失败的状态和错误信息
|
||||
- 确保失败节点的 action 和 error 信息保持不变,直到下次同步清理
|
||||
|
||||
> **说明**:
|
||||
> - `data` / `origin_data`:每次运行从数据源重新获取,保证数据最新
|
||||
> - `depend_ids`:**不持久化**,每次 bind 阶段从 data 的业务字段(如 contract_id, project_id)实时提取
|
||||
> - `binding_status`:持久化用于审计,加载时重置为 `UNCHECKED`,由 bind() 重新判定
|
||||
> - `error`:**阶段1清空**,避免上次错误影响本次运行,新错误会在各阶段重新生成
|
||||
> - `action`:**阶段1保留**用于识别 CREATE 失败的节点,**阶段2清理后重置**
|
||||
> - `status`:**阶段1全部保留**(包括 FAILED、PRECONDITION_FAILED 等),不自动重置
|
||||
> - **CREATE 失败节点会被自动删除并重新加载**,UPDATE/DELETE 失败保留需人工处理
|
||||
> - **UPDATE 操作会跳过 FAILED 节点**,避免覆盖失败状态和错误信息
|
||||
|
||||
### 1.3 绑定记录 vs binding_status
|
||||
|
||||
| 概念 | 存储位置 | 持久性 | 如何改变 |
|
||||
|------|---------|--------|---------|
|
||||
| **绑定记录** | `bindings` 表 | **永久保留** | 只能手工 bind/unbind,或 CREATE 失败自动清理 |
|
||||
| **binding_status** | `nodes` 表 | 保存但可重判 | 每次 bind() 重新判定 |
|
||||
|
||||
### 1.4 CREATE 失败的自动恢复
|
||||
|
||||
当 CREATE 操作失败时,会产生"僵尸绑定":
|
||||
- 绑定记录已建立(local_id → remote_node_id)
|
||||
- 但远程节点的 `data_id` 为空(API 未返回真实 ID)
|
||||
|
||||
**下次同步时的自动恢复流程**:
|
||||
1. 阶段1加载:保留 `action=CREATE`
|
||||
2. 阶段2清理:检测到僵尸绑定,自动清理
|
||||
3. 本地节点恢复为 MISSING 状态
|
||||
4. 策略阶段重新判定,再次尝试 CREATE
|
||||
|
||||
---
|
||||
|
||||
## 2. 人工介入规范
|
||||
|
||||
### 2.1 介入时机
|
||||
|
||||
| 时机 | 场景 | 操作 |
|
||||
|------|------|------|
|
||||
| **运行前** | 查看上次失败记录 | 查看持久化的 error,决定是否修复后重试 |
|
||||
| **bind() 后** | 出现 ABNORMAL/WARNING | 检查数据一致性,手工修复或确认 |
|
||||
| **bind() 后** | 1:N / N:N 映射 | 手工绑定指定远程记录 |
|
||||
| **sync() 后** | 批量失败 | 分析失败原因,决定重试策略 |
|
||||
|
||||
### 2.2 binding_status 与介入需求
|
||||
|
||||
| binding_status | 含义 | 需要介入 | 说明 |
|
||||
|----------------|------|---------|------|
|
||||
| `UNCHECKED` | 未检查 | ❌ | 等待 bind() 判定 |
|
||||
| `NORMAL` | 绑定正常 | ❌ | 自动处理 |
|
||||
| `MISSING` | 无绑定记录 | ❌ | 自动创建 |
|
||||
| `WARNING` | 本地有绑定但远程无数据 | ⚠️ 可选 | 可能是远程删除,需确认 |
|
||||
| `ABNORMAL` | 状态不一致 | ✅ **必须** | 需人工排查 |
|
||||
| `DEPENDENCY_ERROR` | 依赖未就绪 | ❌ | 等依赖解决后自动重试 |
|
||||
|
||||
### 2.3 人工绑定操作
|
||||
|
||||
```python
|
||||
# 手工绑定(1:N 场景)
|
||||
binding_manager.bind(node_id="local_xxx", data_id="remote_xxx")
|
||||
|
||||
# 手工解绑
|
||||
binding_manager.unbind(node_id="local_xxx")
|
||||
```
|
||||
|
||||
绑定记录一旦建立,永不自动改变,只能手工操作。
|
||||
|
||||
### 2.4 职责分工
|
||||
|
||||
| 职责 | 系统自动 | 人工介入 |
|
||||
|------|---------|---------|
|
||||
| 1:1 自动绑定 | ✅ | - |
|
||||
| 1:N / N:N 绑定 | ❌ | ✅ |
|
||||
| NORMAL 节点同步 | ✅ | - |
|
||||
| MISSING 节点创建 | ✅ | - |
|
||||
| CREATE 失败重试 | ✅(自动清理僵尸) | ⚠️(需确认后手动重置) |
|
||||
| UPDATE 失败重试 | ❌(保留FAILED状态) | ✅(需确认后手动重置) |
|
||||
| ABNORMAL 处理 | ❌ | ✅ |
|
||||
| WARNING 确认 | ❌ | ✅(可选) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 总结
|
||||
|
||||
1. **分阶段重置**:
|
||||
- 阶段1(加载时):只重置 binding_status,**保留 action/status/error**
|
||||
- 阶段2(数据加载后):清理 CREATE 失败僵尸,然后重置 action
|
||||
2. **失败状态持久化**:FAILED 状态和 error 信息保留,不自动重试
|
||||
3. **绑定记录**:永久保留,除非 CREATE 失败自动清理或手工操作
|
||||
4. **人工介入**:失败需确认后手动重置,ABNORMAL/WARNING 需人工处理,1:N 绑定需手工指定
|
||||
@@ -0,0 +1,112 @@
|
||||
# 架构分层设计:四层模型
|
||||
|
||||
本架构旨在将同步系统的**数据容器**、**同步逻辑**、**执行层**与**编排流程**完全解耦,提供极简且类型安全的开发体验。
|
||||
|
||||
---
|
||||
|
||||
## 1. 架构概览
|
||||
|
||||
系统分为四层,依赖关系严格从上到下:
|
||||
|
||||
1. **通用层 (Common)**: 定义纯数据结构(Data Container)和基础工具。
|
||||
2. **同步系统层 (Sync System)**: 定义同步行为接口(SyncStrategy)与业务规则。
|
||||
3. **数据源层 (DataSource)**: 实现数据的加载与持久化,属于盲目执行层。
|
||||
4. **编排层 (Pipeline)**: 应用层逻辑,硬编码同步顺序,协调 ID 映射与错误传播。
|
||||
|
||||
---
|
||||
|
||||
## 2. 通用层 (Layer 0: Common)
|
||||
|
||||
本层不包含业务逻辑,仅定义数据契约。
|
||||
|
||||
- **SyncNode[T]**: 核心状态机容器。
|
||||
- `origin_data`: 原始数据(对应 `data_id`)。
|
||||
- `data`: 计算后的最新目标数据。
|
||||
- `data_id`: 业务主键ID。加载时必定有值,CREATE 节点初始为空字符串 `""`(布尔值为 False,可通过校验)。
|
||||
- `action`: 同步意图 (NONE, CREATE, UPDATE, DELETE)。
|
||||
- `status`: 执行状态 (PENDING, IN_PROGRESS, SUCCESS, FAILED, SKIPPED, PRECONDITION_FAILED)。
|
||||
- 详见 [状态定义规范 § 5.A](./状态定义规范.md#5-执行同步状态转换-physical-sync-state-transitions)
|
||||
- `binding_status`: 绑定状态 (UNCHECKED, NORMAL, MISSING, DEPENDENCY_ERROR, ABNORMAL, WARNING)。
|
||||
- 详见 [状态定义规范 § 1](./状态定义规范.md#1-核心状态判定表-core-binding-matrix)
|
||||
- `error`: 异常详情。
|
||||
- **DataCollection**: 节点的集合,提供类型安全的查询和过滤方法。
|
||||
- **BindingManager**:
|
||||
- **ID 映射**: 维护 `local_node_id` <-> `remote_node_id` 的双向映射。
|
||||
- **绑定键**: 使用 `node_id` 作为绑定记录的键,**一致不变**。CREATE 成功后只更新节点的 `data_id`,绑定记录不变。
|
||||
- **持久化**: 将映射关系持久化到存储(如 JSON/数据库)。
|
||||
- **Enums**: `SyncAction`, `SyncStatus`, `BindingStatus` 等。
|
||||
|
||||
---
|
||||
|
||||
## 3. 同步系统层 (Layer 1: Sync System)
|
||||
|
||||
核心业务逻辑层。通过实现 `SyncStrategy` 接口来定义特定实体的同步逻辑。
|
||||
|
||||
- **SyncStrategy[T] 接口**:
|
||||
- `bind()`:
|
||||
- 职责:判定 `binding_status` (NORMAL/MISSING/ABNORMAL/WARNING/DEPENDENCY_ERROR)
|
||||
- 详见 [状态定义规范 § 1-3](./状态定义规范.md)
|
||||
- `create()`:
|
||||
- 职责:处理孤儿节点(MISSING),在对方侧创建新节点并设置 `action=CREATE`
|
||||
- **ID 替换**: 创建新节点时,复制数据并将依赖字段的本地 ID 替换为远程 ID
|
||||
- **内联检查**: 通过 `IDResolver.resolve_and_validate()` 验证依赖 ID 解析
|
||||
- 详见 [状态定义规范 § 4.C](./状态定义规范.md)
|
||||
- `update()`:
|
||||
- 职责:处理差异节点(NORMAL 且有 diff),设置 `action=UPDATE`
|
||||
- **ID 替换**: 准备更新数据时,替换数据中的依赖 ID
|
||||
- **内联检查**: 验证目标节点 data_id 完整性,失败则设置 `PRECONDITION_FAILED`
|
||||
- **FAILED 保护**: 自动跳过 `status=FAILED` 的节点
|
||||
- 详见 [状态定义规范 § 4.A](./状态定义规范.md)
|
||||
---
|
||||
|
||||
## 4. 数据源层 (Layer 2: DataSource)
|
||||
|
||||
作为各个后端的适配器,负责数据加载与持久化。
|
||||
|
||||
- **职责**:
|
||||
- `load_nodes(node_type)`: 从后端加载并返回 `SyncNode` 集合,自动添加到 `DataCollection`。
|
||||
- `save_nodes(nodes)`:
|
||||
- 遍历节点,仅处理 `status == PENDING` 且 `action != NONE` 的节点。
|
||||
- 根据 `action` 执行相应的 CREATE/UPDATE/DELETE 操作。
|
||||
- 执行成功后,更新节点的 `status` 和相关信息(如新生成的 remote_id)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 编排层 (Layer 3: Pipeline)
|
||||
|
||||
最高层级,负责流程编排。
|
||||
|
||||
- **职责**:
|
||||
- **显式顺序**: 直接在代码中按顺序调用同步逻辑(例如:先同步项目,再同步合同)。
|
||||
- **故障传播**: 若前置实体某节点同步失败(`FAILED`),编排器在处理后续依赖节点时可将其标记为 `DEPENDENCY_ERROR`。
|
||||
- **生命周期管理**: 初始化 `BindingManager` 和 `DataCollection`,同步结束后调用持久化方法。
|
||||
|
||||
---
|
||||
|
||||
## 6. ID 映射与对齐:核心流程
|
||||
|
||||
为了解决本地数据引用本地 ID 与远程数据引用远程 ID 的冲突,系统采用以下映射逻辑:
|
||||
|
||||
### 绑定阶段 (Binding)
|
||||
- **时机**: `Strategy.bind`
|
||||
- **目标**: 在 `BindingManager` 中确定 local_id ↔ remote_id 映射
|
||||
- **手段**: 业务键匹配(如 Code 匹配)、历史记录恢复等
|
||||
|
||||
### 执行阶段 (Execution)
|
||||
- **时机**: `Strategy.create()` / `Strategy.update()` 阶段
|
||||
- **目标**: 在创建新节点或准备更新时,将依赖字段的本地 ID 替换为远程 ID
|
||||
- **手段**:
|
||||
- `create()`: 创建对方节点时,复制数据并替换所有依赖 ID
|
||||
- `update()`: 准备更新数据时,替换数据中的依赖 ID
|
||||
- **验证**: `_pre_commit_check` 在 create/update 最后检查,确保所有依赖节点都已有远程 ID
|
||||
|
||||
**注意**: ID 替换在 Strategy 的 create/update 阶段完成,DataSource 只负责盲目执行已准备好的数据。
|
||||
|
||||
---
|
||||
|
||||
## 7. 关键设计原则
|
||||
|
||||
- **删除类型依赖配置**: 依赖关系通过 `Pipeline` 中的代码调用顺序自然表达。
|
||||
- **无状态 DataSource**: 数据源不了解绑定逻辑,只看到 `action`、`status` 和 `binding_status`。
|
||||
- **BindingManager 为核心**: 负责 ID 空间映射和持久化。
|
||||
- **配置驱动**: 通过 `StrategyConfig` 和预设配置(ConfigPresets)灵活控制同步行为。
|
||||
@@ -0,0 +1,342 @@
|
||||
# 同步系统状态定义 (Final Spec)
|
||||
|
||||
本文档定义了同步系统的状态机逻辑。逻辑流转遵循以下顺序:
|
||||
1. **核心状态判定** (Core State)
|
||||
2. **依赖检查与ID解析** (Dependency)
|
||||
3. **自动绑定/发现** (Discovery)
|
||||
4. **策略执行** (Action)
|
||||
|
||||
---
|
||||
|
||||
## 0. 绑定状态枚举 (BindingStatus)
|
||||
|
||||
| 状态值 | 含义 | 来源 | 允许创建 |
|
||||
| :--- | :--- | :--- | :---: |
|
||||
| **UNCHECKED** | 未执行绑定检查 | 加载后的初始状态 | ❌ |
|
||||
| **NORMAL** | 绑定正常 | 核心状态判定 | ❌ |
|
||||
| **MISSING** | 无绑定记录(孤儿) | 核心状态判定 | ✅ |
|
||||
| **WARNING** | 业务键不完整 | 自动绑定阶段 | ❌ |
|
||||
| **ABNORMAL** | 数据损坏 | 核心状态判定 | ❌ |
|
||||
| **DEPENDENCY_ERROR** | 依赖未就绪 | 依赖检查或自动绑定 | ❌ |
|
||||
|
||||
**关键原则**:
|
||||
- **UNCHECKED 阻止创建**:加载后节点状态为 UNCHECKED,只有执行了 `bind()` 后才会转为其他状态
|
||||
- **只有 MISSING 状态才能触发 CREATE**:`create()` 方法只查找 `binding_status == MISSING` 的节点
|
||||
- **如果 bind() 被跳过**(如 skip_sync=True),节点保持 UNCHECKED,不会被创建
|
||||
|
||||
---
|
||||
|
||||
## 1. 核心状态判定表 (Core Binding Matrix)
|
||||
|
||||
**说明**:
|
||||
* **Binding Record Pair**: 数据库中的绑定记录 (必须成对出现,已排除单边绑定)。
|
||||
* **Data Valid**: 指数据是否可读、Schema校验是否通过。
|
||||
* **Warning vs Abnormal**:
|
||||
* `ABNORMAL`: 自身数据损坏。
|
||||
* `WARNING`: 自身健康,但因为对方损坏导致**连接不可用**。
|
||||
|
||||
| Bind Pair (Record) | Local Data (Valid?) | Remote Data (Valid?) | -> | **Local Status** | **Remote Status** | **说明** |
|
||||
| :---: | :---: | :---: | :--- | :--- | :--- | :--- |
|
||||
| **YES** | **YES** | **YES** | -> | **NORMAL** | **NORMAL** | **稳态**。链路完整,数据健康,可进行 Diff/Update。 |
|
||||
| **YES** | **YES** | **NO** | -> | **WARNING** | **ABNORMAL** | **远程损坏**。本地虽好,但链路已断 (Link Degraded)。禁止同步。 |
|
||||
| **YES** | **NO** | **YES** | -> | **ABNORMAL** | **WARNING** | **本地损坏**。远程虽好,但链路已断。禁止同步。 |
|
||||
| **YES** | **NO** | **NO** | -> | **ABNORMAL** | **ABNORMAL** | **双向损坏**。 |
|
||||
| **NO** | **YES** | N/A | -> | **MISSING** | N/A | **本地孤儿**。进入“依赖与发现”流程。 |
|
||||
| **NO** | N/A | **YES** | -> | N/A | **MISSING** | **远程孤儿**。进入“依赖与发现”流程。 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 依赖与业务键解析 (Dependency & ID Resolution)
|
||||
|
||||
**适用范围**: 所有涉及外键依赖 (Foreign Key) 的节点。
|
||||
**前置条件**: 核心状态 = `MISSING` (准备进行自动绑定或新建)。
|
||||
|
||||
在进行 `Auto-Bind` 或 `Create` 之前,必须先尝试构建**远程业务键**。
|
||||
例如:本地 `Contract(proj_id="P1", code="C01")` 想找远程对象,必须先查询 `P1` 对应的远程 ID `RP_99`,转换成 `(RP_99, "C01")` 才能去远程搜索。
|
||||
|
||||
| 依赖项 (Dependency) | 依赖项绑定状态 | -> | **能否构建业务键** | **节点状态** | **说明** |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **无依赖** | N/A | -> | ✅ Yes | **MISSING** | 根节点 (如 Project),直接进入下一阶段。 |
|
||||
| **有依赖** | **NORMAL** 且 `data_id` 非空(`status` 任意) | -> | ✅ Yes | **MISSING** | 依赖项已获得远程ID,可进入下一阶段。 |
|
||||
| **有依赖** | **NORMAL** 且 `data_id` 为空("",含 `status = FAILED`) | -> | ❌ No | **DEPENDENCY_ERROR** | 依赖项未回填ID,阻断绑定与同步。 |
|
||||
| **有依赖** | **MISSING / ABNORMAL** | -> | ❌ No | **DEPENDENCY_ERROR** | **依赖阻断**。父节点未同步或损坏,无法计算远程键,无法绑定,无法创建。 |
|
||||
| **有依赖** | **WARNING** | -> | ❌ No | **DEPENDENCY_ERROR** | 父节点状态不确定(如连接降级),禁止基于此建立新关系。 |
|
||||
|
||||
> **处理策略**: 处于 `DEPENDENCY_ERROR` 状态的节点,其动作强制为 **SKIP** (或 PENDING)。必须先修复父节点。
|
||||
>
|
||||
> **错误信息格式**: `DEPENDENCY_ERROR` 节点的 `error` 字段会包含详细的依赖失败信息:
|
||||
> - `dep_err: not_found: field_name(node_type)=value` - 依赖节点未找到
|
||||
> - `dep_err: field_name: status=FAILED` - 依赖节点状态为 FAILED
|
||||
> - 多个依赖失败时用分号分隔:`dep_err: not_found: project_id(project)=P1; contract_id: status=FAILED`
|
||||
|
||||
---
|
||||
|
||||
## 3. 自动绑定状态处理 (Auto-Binding State Handling)
|
||||
|
||||
此逻辑遵循“去噪后 1:1”原则:只有在排除掉所有健康同步对后,若剩余节点形成绝对的 1:1 关系,才允许自动绑定。
|
||||
|
||||
**配置说明与触发机制**:
|
||||
- **初始化场景**: 通常在系统第一次初始化或首次接入新实体时,配置 `auto_bind = True` 来对齐历史数据。
|
||||
- **后续同步**: 系统在日常同步中不建议开启全局自动绑定。自动绑定仅作为“发现”手段,一旦建立过关系的节点,其后续绑定操作通常仅在“自动创建”逻辑中伴随产生(详见第 4 节孤儿处理)。
|
||||
- **执行前提**: 只有当节点状态为 `MISSING` 且依赖解析成功(`DEPENDENCY_ERROR = False`)时,才会尝试以下探测逻辑。
|
||||
- **业务键完整性**: 若业务键字段缺失(如 `serial_number = null`),直接标记 `binding_status = WARNING`,并在 `node.error` 记录原因(`Auto-bind skipped: missing fields ...`),不参与自动绑定与孤儿创建判定。- **ID字段解析失败**: 若业务键包含ID字段(如 `supplier_id`)且依赖节点未绑定,ID解析失败,标记 `binding_status = DEPENDENCY_ERROR`,阻止孤儿创建。
|
||||
**核心算法**:
|
||||
1. **全集搜索**: 寻找本地/远端所有共享同一个业务键(Business Key)的记录。
|
||||
2. **排除稳态对**: 识别并移除**成对且互绑**的 `NORMAL` 记录。
|
||||
- 只有当本地 A 与远端 B 互为绑定对象,且状态皆为 `NORMAL` 时,才将这一对记录从待判定集合中剔除。
|
||||
- 若出现单边 `NORMAL` 记录(即其配对项不在本次搜索范围内或状态不属于另一端的 `NORMAL`),则不予剔除,视为环境污染项。
|
||||
3. **判定剩余**: 检查排除上述稳态对后的剩余集合(包含 `MISSING`, `ABNORMAL`, `WARNING` 及单边已占用的 `NORMAL` 记录)。
|
||||
|
||||
> **术语**:
|
||||
> - `L_remain` = 本地记录中,排除“成对稳态”后剩余的数量。
|
||||
> - `R_remain` = 远端记录中,排除“成对稳态”后剩余的数量。
|
||||
|
||||
| `L_remain` | `R_remain` | -> | **动作** | **说明** |
|
||||
| :---: | :---: | :--- | :--- | :--- |
|
||||
| **1** | **1** | -> | **BIND (Link)** | **1对1 自动对齐**:仅当两端剩余记录皆为 `MISSING` 且绝对 1:1 时,执行自动绑定。 |
|
||||
| **1** | **1** | -> | **SKIP** | **带障不处理**:若剩余记录中包含 `ABNORMAL` 等异常状态,说明存在历史冲突,不执行自动动作。 |
|
||||
| **N** | **0** | -> | **CREATE** | **可判定缺失**:业务键完整且唯一,本地存在而远端不存在(N:0)时,才允许进入孤儿创建策略。 |
|
||||
| 其他 | 其他 | -> | **SKIP** | **非 1:1 不处理**:存在多对多、多对一或无候选情况,系统保持原状。 |
|
||||
|
||||
**设计优势**:
|
||||
1. **对故障极端敏感**:环境中存在任何 `ABNORMAL` 记录都会阻断自动绑定,强制人工介入处理异常。
|
||||
2. **状态纯净**:失败时不产生任何中间态(如已废弃的 `AMBIGUOUS`),保持语义清晰。
|
||||
3. **静默自愈**: 当外界清理了环境且满足 1:1 条件后,系统下次同步会自动完成绑定。
|
||||
|
||||
### 3.1 空数据处理策略
|
||||
|
||||
**原则**:**空数据不推送**。
|
||||
|
||||
**空数据定义**:
|
||||
- 初始化时创建但未编辑的业务记录(如空合同、空施工任务)
|
||||
- 业务键字段为空或关键字段缺失的记录
|
||||
|
||||
**处理方式**:
|
||||
- 在自动绑定阶段,若业务键字段缺失,标记 `binding_status = WARNING`,记录原因
|
||||
- 不参与自动绑定与孤儿创建判定
|
||||
- 不推送到远程系统
|
||||
|
||||
**设计理由**:
|
||||
1. **远程系统简化**:远程只需处理完整数据,无需兼容空数据校验逻辑
|
||||
2. **避免垃圾数据**:空数据通常会被本地删除,若已推送则清理复杂
|
||||
3. **数据质量保障**:远程系统只能看到本地已正确编辑保存的业务
|
||||
|
||||
**配置方式**(Strategy 层):
|
||||
```python
|
||||
# 在 Strategy 配置中指定必填字段
|
||||
default_config = StrategyConfig(
|
||||
auto_bind_fields=["contract_id", "task_type"], # 业务键字段
|
||||
# 如果这些字段为空,节点将被标记为 WARNING 而非 MISSING
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 动作策略表 (Action Policy Matrix)
|
||||
|
||||
此表定义了在特定状态下,`execute` 阶段允许产生的 **意图行动 (`SyncAction`)**。
|
||||
|
||||
#### A. 稳态更新 (NORMAL)
|
||||
适用于已有绑定关系且链路健康的节点。
|
||||
|
||||
| 状态 | 动作条件 | 执行动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **NORMAL** | `compute_diff` 判定存在差异 | **UPDATE** |
|
||||
| **NORMAL** | `compute_diff` 判定无差异 | **NONE** |
|
||||
|
||||
#### B. 异常处理 (阻断态)
|
||||
处于这些状态的节点,引擎会自动中止后续的读写操作。
|
||||
|
||||
| 状态 | 说明 | 动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **DEPENDENCY_ERROR** | 父节点缺失/异常同步导致阻断 | **NONE** |
|
||||
| **ABNORMAL / WARNING** | 数据损坏或链路降级,需人工修复 | **NONE** |
|
||||
|
||||
#### C. 孤儿处理 (Create Only)
|
||||
适用于最终探测状态为 **MISSING** 且无法/不满足自动绑定的节点。
|
||||
|
||||
**本地孤儿 (Local Orphan)**: 本地有,远程无。
|
||||
| 策略配置 (`local_orphan_action`) | 对应的同步模式 | 动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **"create_remote"** | Push (本地推远端) | **CREATE** |
|
||||
| **"delete_local"** | Pull (远端拉本地) | **报错 (未实现)** |
|
||||
| **"none"** | Any | **NONE** |
|
||||
|
||||
**远程孤儿 (Remote Orphan)**: 远程有,本地无。
|
||||
| 策略配置 (`remote_orphan_action`) | 对应的同步模式 | 动作 (`SyncAction`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **"create_local"** | Pull (远端拉本地) | **CREATE** |
|
||||
| **"delete_remote"** | Push (本地推远端) | **报错 (未实现)** |
|
||||
| **"none"** | Any | **NONE** |
|
||||
|
||||
---
|
||||
|
||||
## 5. 执行同步状态转换 (Physical Sync State Transitions)
|
||||
|
||||
在策略执行完成、设置好 `action` 后,DataSource 层负责执行实际的同步操作并更新 `status` 字段。
|
||||
|
||||
### A. 执行状态枚举 (SyncStatus)
|
||||
|
||||
| 状态值 | 含义 | 适用场景 |
|
||||
| :--- | :--- | :--- |
|
||||
| **PENDING** | 待执行 | 初始状态、无动作的节点 |
|
||||
| **IN_PROGRESS** | 执行中 | 异步接口已提交,等待结果回调 |
|
||||
| **SUCCESS** | 执行成功 | 同步操作完成且成功 |
|
||||
| **FAILED** | 执行失败 | 同步操作失败,`error` 字段记录原因 |
|
||||
| **SKIPPED** | 已跳过 | 节点被主动跳过(如依赖未满足) |
|
||||
| **PRECONDITION_FAILED** | 前置条件失败 | create/update 内部验证发现问题 |
|
||||
|
||||
### B. 执行转换矩阵
|
||||
|
||||
#### 同步接口(一步式)
|
||||
|
||||
适用于同步 API(调用后立即返回成功/失败)。
|
||||
|
||||
| 输入: action | API 调用结果 | → | 输出: status | 副作用 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **CREATE** | 成功返回 (200/201) | → | **SUCCESS** | `data_id` 设置为远程返回的ID |
|
||||
| **CREATE** | 失败返回 (4xx/5xx) | → | **FAILED** | `error` 记录错误信息 |
|
||||
| **UPDATE** | 成功返回 (200) | → | **SUCCESS** | - |
|
||||
| **UPDATE** | 失败返回 (4xx/5xx) | → | **FAILED** | `error` 记录错误信息 |
|
||||
| **DELETE** | 成功返回 (200/204) | → | **SUCCESS** | 节点可能被移除 |
|
||||
| **DELETE** | 失败返回 (4xx/5xx) | → | **FAILED** | `error` 记录错误信息 |
|
||||
| **NONE** | - | → | **PENDING** | 不执行,保持原状 |
|
||||
|
||||
#### 异步接口(两步式)
|
||||
|
||||
适用于异步 API(提交后需要轮询或回调获取结果)。
|
||||
|
||||
| 输入: action | API 提交结果 | → | 输出: status | 后续操作 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **CREATE** | 提交成功 (202 Accepted) | → | **IN_PROGRESS** | 记录 task_id,等待轮询 |
|
||||
| **CREATE** | 提交失败 (4xx/5xx) | → | **FAILED** | `error` 记录错误 |
|
||||
| **IN_PROGRESS** | 轮询返回成功 | → | **SUCCESS** | `data_id` 设置为远程ID |
|
||||
| **IN_PROGRESS** | 轮询返回失败 | → | **FAILED** | `error` 记录错误 |
|
||||
| **IN_PROGRESS** | 超时未完成 | → | **FAILED** | `error` 记录 "Timeout" |
|
||||
|
||||
### B+. Handler 降级(action 取消)
|
||||
|
||||
> **代码实现**:各 `domain/*/api_handler.py` 中的 `update()` 方法。
|
||||
|
||||
当 Handler 在构建 API 请求数据时,发现实际无需更新的字段(如 schema 校验后所有字段与远程一致),
|
||||
Handler 会主动将节点的 `action` 从 `UPDATE` 降级为 `NONE`:
|
||||
|
||||
```
|
||||
action=UPDATE → Handler 校验 → 无实际变更字段 → action=NONE(不提交 API)
|
||||
```
|
||||
|
||||
此机制确保 DataSource 不会向远程发送无意义的空更新请求。
|
||||
|
||||
### C. 关键副作用
|
||||
|
||||
| 动作 | 成功时的副作用 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| **CREATE** | 临时绑定已建立 | 绑定关系可在提交前创建,用于推送与追踪;是否成功不影响该绑定存在 |
|
||||
| **CREATE** | 设置 `data_id` | 成功后从API响应中提取远程分配的ID,更新到节点 |
|
||||
| **CREATE** | 回写 `data` 主键 | DataSource 将远程返回的ID写回 `SyncNode.data`(如 `id`/`*_id` 字段) |
|
||||
| **CREATE** | 更新绑定记录 | 若使用临时ID,成功后替换为真实的远程ID |
|
||||
| **UPDATE** | 更新 `origin_data` | 将当前 `data` 保存为新的 `origin_data` |
|
||||
| **DELETE** | 移除绑定记录 | 删除成功后,清除对应的绑定关系 |
|
||||
|
||||
### D. 错误处理
|
||||
|
||||
| 错误类型 | 记录方式 | 重试策略 |
|
||||
| :--- | :--- | :--- |
|
||||
| **网络错误** | `error = "Network timeout"` | 可重试 |
|
||||
| **权限错误** | `error = "403 Forbidden"` | 不可重试,需人工介入 |
|
||||
| **数据校验错误** | `error = "Validation failed: ..."` | 不可重试,需修复数据 |
|
||||
| **依赖缺失** | `status = PRECONDITION_FAILED` | 不执行,等待依赖修复 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 同步检查规范 (Sync Check Specification)
|
||||
|
||||
在执行同步前后,需要进行状态检查以确保操作的合法性和完整性。
|
||||
|
||||
### A. 内联前置检查(create/update 阶段)
|
||||
|
||||
> **实现说明**:原 `_pre_commit_check` 方法已移除(保留空壳兼容接口)。
|
||||
> 所有有效检查已内联到 `strategy_ops/create_ops.py::add_create_action()` 和 `strategy_ops/update_ops.py::add_update_action()` 中。
|
||||
|
||||
**create() 阶段内联检查**:
|
||||
|
||||
| 检查类别 | 检查条件 | 不通过时 | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **数据完整性** | `src_node.get_data()` 不为空 | 跳过该节点,记录日志 | MISSING 但数据为空 |
|
||||
| **依赖 ID 解析** | `id_resolver.resolve_and_validate()` 成功 | `binding_status → DEPENDENCY_ERROR` | 依赖字段无法解析到目标系统 ID |
|
||||
|
||||
**update() 阶段内联检查**:
|
||||
|
||||
| 检查类别 | 检查条件 | 不通过时 | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **FAILED 保护** | `src_node.status != FAILED` | 跳过该节点 | 不覆盖上次失败的状态和错误 |
|
||||
| **数据完整性** | `src_node.get_data()` 不为空 | 跳过该节点 | NORMAL 但数据为空 |
|
||||
| **目标节点存在** | 通过绑定找到目标节点 | 跳过该节点 | 绑定记录指向的节点不在集合中 |
|
||||
| **data_id 完整性** | `target_node.data_id` 非空 | `status → PRECONDITION_FAILED` | UPDATE 必须有业务主键 |
|
||||
| **依赖 ID 解析** | `id_resolver.resolve_and_validate()` 成功 | `status → PRECONDITION_FAILED` | 依赖字段无法解析到目标系统 ID |
|
||||
| **差异检测** | `_needs_update()` 返回 True | 跳过该节点 | 无差异则不更新 |
|
||||
|
||||
> **注意**:以下检查项在当前实现中 **未覆盖**【未实现】:
|
||||
> - 状态合法性:`binding_status` 必须是已知状态
|
||||
> - 动作合法性:`CREATE/UPDATE` 只能用于 `NORMAL` 节点
|
||||
> - 绑定一致性:`NORMAL` 节点必须有绑定记录
|
||||
|
||||
### B. 同步后检查 (Post-Sync Check)
|
||||
|
||||
**目标**: 验证同步结果的完整性,发现残留问题。
|
||||
|
||||
> **实现说明**:当前 `_stage4_post_sync_check` 只打印摘要表格,不做异常检测。以下检查项均为【未实现】。
|
||||
|
||||
#### 检查项清单【未实现】
|
||||
|
||||
| 检查类别 | 检查条件 | 异常情况 | 严重程度 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **CREATE 完成性** | CREATE 节点应该有 `data_id` | `action = CREATE, status = SUCCESS` 但 `data_id = ""` | 🔴 ERROR |
|
||||
| **CREATE 绑定** | CREATE 节点应该有绑定记录 | CREATE 成功但无绑定 | 🔴 ERROR |
|
||||
| **UPDATE 完成性** | UPDATE 节点应该成功 | `action = UPDATE` 但 `status = FAILED` | ⚠️ WARNING |
|
||||
| **绑定保持** | UPDATE 节点的绑定应该保持 | UPDATE 后绑定记录丢失 | 🔴 ERROR |
|
||||
| **残留异常** | 不应有 ABNORMAL 节点 | 同步后仍有 `binding_status = ABNORMAL` | ⚠️ WARNING |
|
||||
| **残留依赖错误** | 不应有 DEPENDENCY_ERROR | 同步后仍有依赖阻断 | ⚠️ WARNING |
|
||||
|
||||
#### 统计指标
|
||||
|
||||
| 指标 | 计算方式 | 用途 |
|
||||
| :--- | :--- | :--- |
|
||||
| **成功率** | `SUCCESS / (CREATE + UPDATE)` | 评估同步质量 |
|
||||
| **异常率** | `(ABNORMAL + WARNING) / total` | 发现数据质量问题 |
|
||||
| **阻断率** | `DEPENDENCY_ERROR / total` | 发现依赖关系问题 |
|
||||
|
||||
#### 决策规则
|
||||
|
||||
| 检查结果 | ERROR 数量 | 决策 |
|
||||
| :--- | :--- | :--- |
|
||||
| ✅ 通过 | 0 | **继续持久化**,正常结束 |
|
||||
| ⚠️ 有警告 | 0, WARNING ≥1 | **继续持久化**,打印警告报告 |
|
||||
| ❌ 有错误 | ≥1 | **继续持久化**(已同步无法回滚),打印错误报告 |
|
||||
|
||||
> **注意**: Post-Sync Check 即使有 ERROR 也不会终止流程,因为同步已经执行,无法回滚。检查目的是发现问题并记录,供后续修复。
|
||||
|
||||
---
|
||||
|
||||
## 附录: 状态字段说明
|
||||
|
||||
### SyncNode 核心字段
|
||||
|
||||
| 字段 | 类型 | 设置阶段 | 含义 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `binding_status` | BindingStatus | Bind 阶段 | 绑定健康状态 |
|
||||
| `action` | SyncAction | Create/Update 阶段 | 待执行动作 |
|
||||
| `status` | SyncStatus | Physical Sync 阶段 | 执行结果状态 |
|
||||
| `data_id` | str | 数据加载 / CREATE 后 | 业务主键ID(CREATE 前为 "") |
|
||||
| `depend_ids` | List[str] | 数据加载 | 依赖节点的 node_id 列表 |
|
||||
| `error` | str \| None | Physical Sync 阶段 | 错误信息(失败时) |
|
||||
|
||||
### 状态流转时序
|
||||
|
||||
```
|
||||
[数据加载] [Bind] [Create/Update] [Physical Sync]
|
||||
binding_status: UNCHECKED → NORMAL/MISSING/... → (保持) → (保持)
|
||||
action: NONE → NONE → CREATE/UPDATE → (保持)
|
||||
status: PENDING → PENDING → PENDING → SUCCESS/FAILED
|
||||
data_id: 从源加载 → (保持) → 可能为 "" → CREATE 后设置
|
||||
```
|
||||
@@ -0,0 +1,498 @@
|
||||
# 状态机形式化规范
|
||||
|
||||
本文档用 **Guard-Event-Action (GEA)** 形式严格定义节点状态机。
|
||||
所有转换以代码实现为准,模糊之处在文档中显式标注。
|
||||
|
||||
> **代码基线**
|
||||
> - 枚举: `sync_system_new/common/types.py`
|
||||
> - 决策引擎: `sync_system_new/sync_system/decision.py`
|
||||
> - 重置策略: `sync_system_new/common/state_reset.py`
|
||||
> - 同步策略: `sync_system_new/sync_system/strategy.py`
|
||||
> - 物理同步: `sync_system_new/datasource/datasource.py`
|
||||
|
||||
> **配置基线(状态机真源)**
|
||||
> - `sync_system_new/state_machine/node_state_machine.yaml`
|
||||
|
||||
### 2026-02 对齐说明(重构前必读)
|
||||
|
||||
以下语义以 `node_state_machine.yaml` 为准,用于修正文档中易混淆点:
|
||||
|
||||
1. **E12a 为什么从 S01 出发?**
|
||||
- `S01` 只约束**源节点**是 NORMAL/NONE/PENDING 且有 `data_id`。
|
||||
- `E12a` 的 guard 是 `target_has_data_id=false`,检查对象是**目标节点**。
|
||||
- 所以“源节点在 S01”与“E12a 触发前置失败”并不冲突。
|
||||
|
||||
2. **S01 会不会触发创建?**
|
||||
- 当前配置中,create 的入口状态是 `S02(MISSING)`,不是 `S01`。
|
||||
- `S01` 进入的是 update_prepare(E12/E13/E14)。
|
||||
|
||||
3. **N:0 + create_enabled=true 的当前行为**
|
||||
- 自动绑定分支 `E08f`:`S02 -> S01`,并 `emit spawn_target_node_state: S06`。
|
||||
- create_prepare 分支 `E09b` 也可在检查成功后 `S02 -> S01 + spawn S06`。
|
||||
- 即:源节点不会停在“等待创建结果”的专用状态;创建执行结果体现在目标创建节点链路 `S06 -> S10/S11/S12/S13`。
|
||||
|
||||
4. **旧章节中的事件编号偏差**
|
||||
- 本文后续仍有部分“E11a/E11b/…”旧编号描述,已与当前 YAML 不一致。
|
||||
- 进行代码重构时,优先依据 YAML 的 `E08/E09/E10/E12/E13/E14/E15..E20`。
|
||||
|
||||
---
|
||||
|
||||
## §1 状态空间定义
|
||||
|
||||
### §1.1 状态维度
|
||||
|
||||
节点携带 **三个独立的状态字段** 和 **两个辅助字段**:
|
||||
|
||||
| 字段 | 枚举 | 值域 | 语义 |
|
||||
|------|------|------|------|
|
||||
| **B** – `binding_status` | `BindingStatus` | `UNCHECKED` · `NORMAL` · `MISSING` · `ABNORMAL` · `WARNING` · `DEPENDENCY_ERROR` | 绑定健康度 |
|
||||
| **A** – `action` | `SyncAction` | `NONE` · `CREATE` · `UPDATE` · `DELETE` | 待执行动作 |
|
||||
| **S** – `status` | `SyncStatus` | `PENDING` · `IN_PROGRESS` · `SUCCESS` · `FAILED` · `SKIPPED` · `PRECONDITION_FAILED` | 执行结果 |
|
||||
|
||||
辅助字段(影响 Guard 但不是状态维度):
|
||||
|
||||
| 字段 | 类型 | 语义 |
|
||||
|------|------|------|
|
||||
| `data_id` | `str` | 业务主键(空串 `""` = 尚未从远程获取) |
|
||||
| `error` | `str \| None` | 最近一次错误信息 |
|
||||
|
||||
理论组合 = 6 × 4 × 6 = **144**,实际可达 ≈ **23** 种。
|
||||
|
||||
### §1.2 可达状态枚举
|
||||
|
||||
以下列出所有在正常流程中可以到达的 `(binding_status, action, status)` 三元组。
|
||||
|
||||
| # | binding_status | action | status | 语义 | 产生阶段 |
|
||||
|---|---|---|---|------|---------|
|
||||
| R1 | UNCHECKED | NONE | PENDING | 首次加载 | 数据加载 |
|
||||
| R2 | UNCHECKED | NONE | SUCCESS | 从持久化恢复(上轮成功)后重置 | 阶段1/2重置 |
|
||||
| R3 | UNCHECKED | NONE | FAILED | 从持久化恢复(上轮失败)后重置 | 阶段1/2重置 |
|
||||
| R4 | UNCHECKED | NONE | SKIPPED | 从持久化恢复(上轮跳过)后重置 | 阶段1/2重置 |
|
||||
| R5 | UNCHECKED | NONE | PRECONDITION_FAILED | 从持久化恢复(上轮前置失败)后重置 | 阶段1/2重置 |
|
||||
| R6 | NORMAL | NONE | PENDING | 绑定正常,无需操作(首次) | bind.p1 |
|
||||
| R7 | NORMAL | NONE | SUCCESS | 绑定正常,无需操作(历史成功) | bind.p1 |
|
||||
| R8 | NORMAL | NONE | FAILED | 绑定正常但上次失败,被 FAILED 保护 | bind.p1 |
|
||||
| R9 | MISSING | NONE | PENDING | 孤儿,等待自动绑定或创建(首次) | bind.p1 |
|
||||
| R10 | MISSING | NONE | SUCCESS | 孤儿(历史成功但绑定丢失?) | bind.p1 |
|
||||
| R11 | ABNORMAL | NONE | * | 数据损坏,需人工 | bind.p1 |
|
||||
| R12 | WARNING | NONE | * | 多候选/对方损坏,需人工 | bind.p1/p3 |
|
||||
| R13 | DEPENDENCY_ERROR | NONE | PENDING | 依赖不满足 | bind.p2/p3/create |
|
||||
| R14 | NORMAL | CREATE | PENDING | 准备创建(目标节点) | create |
|
||||
| R15 | NORMAL | CREATE | IN_PROGRESS | 异步创建进行中 | sync |
|
||||
| R16 | NORMAL | CREATE | SUCCESS | 创建成功 | sync |
|
||||
| R17 | NORMAL | CREATE | FAILED | 创建失败 | sync |
|
||||
| R18 | NORMAL | UPDATE | PENDING | 准备更新(目标节点) | update |
|
||||
| R19 | NORMAL | UPDATE | IN_PROGRESS | 异步更新进行中 | sync |
|
||||
| R20 | NORMAL | UPDATE | SUCCESS | 更新成功 | sync |
|
||||
| R21 | NORMAL | UPDATE | FAILED | 更新失败 | sync |
|
||||
| R22 | NORMAL | UPDATE | PRECONDITION_FAILED | 更新前置条件失败 | update |
|
||||
| R23 | NORMAL | CREATE | SKIPPED | 创建被 Handler 跳过 | sync |
|
||||
|
||||
> **不可达组合(示例)**:
|
||||
> - `(MISSING, UPDATE, *)` — MISSING 节点不可能被安排 UPDATE
|
||||
> - `(ABNORMAL, CREATE, *)` — ABNORMAL 节点不可能被安排 CREATE
|
||||
> - `(*, DELETE, *)` — DELETE 尚未实现
|
||||
> - `(UNCHECKED, CREATE, *)` — UNCHECKED 是瞬态,在 bind 之前不会有 CREATE
|
||||
> - `(DEPENDENCY_ERROR, UPDATE, *)` — DEPENDENCY_ERROR 节点不可能进入 update 流程
|
||||
|
||||
### §1.3 辅助字段约束
|
||||
|
||||
| 对应状态 | binding_status | action | status | data_id 约束 | error 约束 |
|
||||
|---------|---|---|---|-------------|-----------|
|
||||
| R14 | NORMAL | CREATE | PENDING | `""` (待远程返回) | None |
|
||||
| R16 | NORMAL | CREATE | SUCCESS | 非空 (远程回填) | None |
|
||||
| R17 | NORMAL | CREATE | FAILED | `""` (未回填) | 非空 |
|
||||
| R22 | NORMAL | UPDATE | PRECONDITION_FAILED | * | 非空 |
|
||||
| R13 | DEPENDENCY_ERROR | NONE | PENDING | * | 非空 |
|
||||
|
||||
---
|
||||
|
||||
## §2 不变量 (Invariants)
|
||||
|
||||
以下约束在**任何事件执行后**都必须成立。违反即为 Bug。
|
||||
|
||||
```
|
||||
INV-1 B = UNCHECKED ⟹ A = NONE
|
||||
(UNCHECKED 是瞬态,在 bind 之前不允许有动作)
|
||||
|
||||
INV-2 B ∈ {ABNORMAL, WARNING, DEPENDENCY_ERROR} ⟹ A = NONE
|
||||
(阻断态节点不允许执行任何同步动作)
|
||||
|
||||
INV-3 B = MISSING ⟹ A ∈ {NONE, CREATE}
|
||||
(MISSING 节点只能等待创建或保持不动)
|
||||
|
||||
INV-4 A = CREATE ⟹ B = NORMAL
|
||||
(CREATE 动作只出现在目标节点上,其 binding_status 已被设为 NORMAL)
|
||||
|
||||
INV-5 A = UPDATE ⟹ B = NORMAL
|
||||
(UPDATE 动作只对 NORMAL 节点执行)
|
||||
|
||||
INV-6 S = IN_PROGRESS ⟹ A ∈ {CREATE, UPDATE, DELETE}
|
||||
(只有提交过 API 的节点才可能处于 IN_PROGRESS)
|
||||
|
||||
INV-7 S = PRECONDITION_FAILED ⟹ A = UPDATE
|
||||
(PRECONDITION_FAILED 只在 update 阶段产生)
|
||||
|
||||
INV-8 A = CREATE ∧ S = SUCCESS ⟹ data_id ≠ ""
|
||||
(创建成功必须回填 data_id)
|
||||
|
||||
INV-9 S = FAILED ⟹ error ≠ None
|
||||
(失败必须有错误信息)
|
||||
|
||||
INV-10 B = DEPENDENCY_ERROR ⟹ error ≠ None
|
||||
(依赖阻断必须有错误信息)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §3 事件与转换
|
||||
|
||||
### §3.1 事件总览图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 节点生命周期事件流 │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
|
||||
持久化恢复 策略层 (Strategy) 执行层 (DataSource)
|
||||
═══════════ ══════════════════════════════════ ══════════════════════════
|
||||
┌──────────────────────────────┐
|
||||
┌──────┐ │ bind() │ ┌──────────────────────┐
|
||||
│E01 │──────────▶│ E04 ─┐ │ │ sync_all() │
|
||||
│RESET1│ │ E05 ├─ phase1: core_state │ │ │
|
||||
└──┬───┘ │ E06 ─┘ │ │ E12 SYNC_OK │
|
||||
│ │ E07 ── phase2: dep_check │ ┌───▶│ E13 SYNC_FAIL │
|
||||
┌──▼───┐ │ E08 ─┐ │ │ │ E14 SYNC_ASYNC │
|
||||
│E02 │ │ E09 ├─ phase3: auto_bind │ │ │ E15 SYNC_TIMEOUT │
|
||||
│ZOMBIE│ │ E10 ─┘ │ │ │ E16 HANDLER_SKIP │
|
||||
└──┬───┘ └──────────────────────────────┘ │ │ E17 HANDLER_DOWN │
|
||||
│ ┌──────────────────────────────┐ │ └──────────────────────┘
|
||||
┌──▼───┐ │ create() / update() │ │
|
||||
│E03 │──────────▶│ E11a CREATE_OK │────┘
|
||||
│RESET2│ │ E11b CREATE_DEP_FAIL │
|
||||
└──────┘ │ E11c UPDATE_DIFF │
|
||||
│ E11d UPDATE_PRECOND_FAIL │
|
||||
│ E11e UPDATE_SKIP_FAILED │
|
||||
└──────────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
### §3.2 状态转换详解
|
||||
|
||||
本节按 Pipeline 执行阶段组织。每个阶段包含:
|
||||
1. **状态转换图**:状态(R 编号)为节点,事件(E 编号)为有向边
|
||||
2. **转换表**:每个事件的精确规格——起始状态、判断条件、结束状态、副作用
|
||||
|
||||
---
|
||||
|
||||
#### 🔄 阶段 0:重置
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
╔═══════════════════════════════════════╗
|
||||
║ 任意持久化终态 (R6 ~ R23) ║
|
||||
╚═══════════════════╤═══════════════════╝
|
||||
│ E01
|
||||
▼
|
||||
┌────────────────────────────────────────┐ E02
|
||||
│ 瞬态: UNCHECKED │────────────▶ [节点删除 + 解除绑定]
|
||||
│ (action 保留, status 保留, error=None) │
|
||||
└────────────────────┬──────────────────┘
|
||||
│ E03 (存活节点)
|
||||
▼
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ [R1] UNCHECKED, NONE, PENDING ← 首次加载 ║
|
||||
║ [R2] UNCHECKED, NONE, SUCCESS ← 上轮成功 ║
|
||||
║ [R3] UNCHECKED, NONE, FAILED ← 上轮失败 ║
|
||||
║ [R4] UNCHECKED, NONE, SKIPPED ← 上轮跳过 ║
|
||||
║ [R5] UNCHECKED, NONE, PRECONDITION_FAILED ← 上轮前置 ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E01**: PHASE1_RESET | R6~R23 (任意持久化终态) | 节点从持久化加载 | 瞬态 (UNCHECKED, action 保留, status 保留) | error → None; data/origin_data → None |
|
||||
| **E02**: ZOMBIE_KILL | 瞬态 | action = CREATE ∧ (status = FAILED ∨ data_id = "") | **节点删除** | 解除绑定关系; 对 local/remote 两侧都扫描 |
|
||||
| **E03**: ACTION_RESET | 瞬态 (存活节点) | E02 完成后所有存活节点 | R1 / R2 / R3 / R4 / R5 (按原 status 分) | action → NONE |
|
||||
|
||||
> **代码**: `NodeStateReset.get_phase1_reset_defaults()` · `cleanup_create_failed_zombies()` · `reset_action_for_nodes()`
|
||||
|
||||
---
|
||||
|
||||
#### 🔗 阶段 1:Bind
|
||||
|
||||
Bind 由三个子阶段串行执行。后一阶段只处理前一阶段的遗留 MISSING 节点。
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
[R1~R5] UNCHECKED, NONE, *
|
||||
│
|
||||
│ ══════════ Phase 1: 核心状态判定 ══════════
|
||||
│
|
||||
├── E04 (有绑定, 双方数据 VALID) ───────────▶ [R6/R7/R8] NORMAL ──────▶ 出口 ✅
|
||||
├── E04 (有绑定, 自身数据缺失/损坏) ────────▶ [R11] ABNORMAL ─────────▶ 出口 🔒
|
||||
├── E04 (有绑定, 对方数据缺失/损坏) ────────▶ [R12] WARNING ──────────▶ 出口 🔒
|
||||
│
|
||||
└── E05 (无绑定记录) ───────────────────────▶ [R9] MISSING
|
||||
│
|
||||
══════════ Phase 2: 依赖检查 ══════════ │
|
||||
│
|
||||
├── E06 (data = None) ──────────────────────▶ [R11] ABNORMAL ──────▶ 出口 🔒
|
||||
├── E07 (依赖节点不满足) ───────────────────▶ [R13] DEP_ERROR ─────▶ 出口 🔒
|
||||
│ (无依赖配置 或 依赖全部满足 → 继续 ▼)
|
||||
│
|
||||
══════════ Phase 3: 自动绑定 ══════════
|
||||
│
|
||||
├── E08 (auto_bind 关闭) ──────────────────▶ [R12] WARNING ────────▶ 出口 🔒
|
||||
├── E09 (去噪后 1:1 匹配成功) ─────────────▶ [R6] NORMAL ─────────▶ 出口 ✅
|
||||
├── E10a (去噪后非 1:1, 多候选) ───────────▶ [R12] WARNING ────────▶ 出口 🔒
|
||||
├── E10b (业务键字段缺失) ─────────────────▶ [R12] WARNING ────────▶ 出口 🔒
|
||||
├── E10c (业务键中 ID 字段解析失败) ───────▶ [R13] DEP_ERROR ─────▶ 出口 🔒
|
||||
│
|
||||
└── (1:0 无远程匹配)
|
||||
├── create_enabled = True → [R9] MISSING ──────────────▶ 进入 create
|
||||
└── create_enabled = False → [R12] WARNING ─────────────▶ 出口 🔒
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E04**: BIND_PAIRED | R1~R5 | 有绑定记录 ∧ 双方数据 VALID | R6 (PENDING) / R7 (SUCCESS) / R8 (FAILED) — status 保持 | 远程节点同步设置 binding_status |
|
||||
| **E04**: BIND_PAIRED (自身异常) | R1~R5 | 有绑定记录 ∧ 本方数据缺失或损坏 | R11 (ABNORMAL) | 对方节点设为 WARNING |
|
||||
| **E04**: BIND_PAIRED (对方异常) | R1~R5 | 有绑定记录 ∧ 对方数据缺失或损坏 | R12 (WARNING) | 对方节点设为 ABNORMAL |
|
||||
| **E05**: BIND_ORPHAN | R1~R5 | 无绑定记录 | R9 (MISSING, NONE, status 保持) | — |
|
||||
| **E06**: DATA_NULL | R9 | binding_status = MISSING ∧ data = None | R11 (ABNORMAL) | error = "数据损坏: 节点数据为空或不存在" |
|
||||
| **E07**: DEP_CHECK_FAIL | R9 | depend_fields 配置非空 ∧ ∃依赖节点: 不存在 ∨ status ≠ NORMAL ∨ data_id 为空 | R13 (DEPENDENCY_ERROR) | error = "依赖项不满足: ..."; depend_ids 填充 |
|
||||
| **E08**: AUTOBIND_DISABLED | R9 | auto_bind = False 或 auto_bind_fields 为空 | R12 (WARNING) | — |
|
||||
| **E09**: AUTOBIND_OK | R9 | 去噪后 local:remote = 1:1 ∧ 双方都是 MISSING | R6 (NORMAL) | 建立绑定记录; 双方都设为 NORMAL |
|
||||
| **E10a**: AUTOBIND_AMBIGUOUS | R9 | 去噪后非 1:1 (多候选) | R12 (WARNING) | error += "存在多个候选节点" |
|
||||
| **E10b**: AUTOBIND_KEY_MISSING | R9 | auto_bind_fields 中有字段不存在于 data | R12 (WARNING) | error += "缺少业务键字段: ..." |
|
||||
| **E10c**: AUTOBIND_ID_FAIL | R9 | 业务键包含 ID 字段 ∧ ID 解析失败 | R13 (DEPENDENCY_ERROR) | error = "业务键中的ID字段解析失败: ..." |
|
||||
| **E10d**: ORPHAN_CREATE_DISABLED | R9 | 去噪后 1:0 ∧ create_enabled = False | R12 (WARNING) | error += "孤儿且不允许自动创建" |
|
||||
|
||||
> **E04 核心状态矩阵** (完整查表):
|
||||
>
|
||||
> | | 远程: VALID | 远程: ABSENT | 远程: INVALID |
|
||||
> |---|---|---|---|
|
||||
> | **本地: VALID** | 本:NORMAL 远:NORMAL | 本:WARNING 远:ABNORMAL | 本:WARNING 远:ABNORMAL |
|
||||
> | **本地: ABSENT** | 本:ABNORMAL 远:WARNING | 本:ABNORMAL 远:ABNORMAL | — |
|
||||
> | **本地: INVALID** | 本:ABNORMAL 远:WARNING | — | 本:ABNORMAL 远:ABNORMAL |
|
||||
>
|
||||
> 不在矩阵中的组合 → 默认 (ABNORMAL, ABNORMAL)
|
||||
|
||||
> **代码**: `SyncDecisionEngine.determine_core_status()` · `strategy_ops/bind_ops.py::phase_core_state()` · `strategy_ops/bind_ops.py::check_dependencies_for_nodes()` · `strategy_ops/bind_ops.py::phase_auto_binding()`
|
||||
|
||||
---
|
||||
|
||||
#### ⚡ 阶段 2:Create / Update
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
═══════════════ Create ═══════════════
|
||||
|
||||
[R9] MISSING, NONE, PENDING (源节点, data ≠ None)
|
||||
│
|
||||
├── E11a (ID 解析成功) ────▶ 源节点: [R9] → [R6] NORMAL
|
||||
│ 新建目标节点: → [R14] NORMAL, CREATE, PENDING
|
||||
│ + 建立绑定记录, 目标 data_id = ""
|
||||
│
|
||||
└── E11b (ID 解析失败) ────▶ 源节点: [R9] → [R13] DEPENDENCY_ERROR
|
||||
|
||||
|
||||
═══════════════ Update ═══════════════
|
||||
|
||||
[R6/R7] NORMAL, NONE, PENDING/SUCCESS (源节点, status ≠ FAILED)
|
||||
│
|
||||
├── E11c (差异检测通过) ────▶ 目标节点 → [R18] NORMAL, UPDATE, PENDING
|
||||
├── E11d.1 (目标 data_id="") ▶ 目标节点 → [R22] status = PRECONDITION_FAILED
|
||||
├── E11d.2 (ID 解析失败) ───▶ 目标节点 → [R22] action = UPDATE, status = PRECOND_FAIL
|
||||
└── (无差异) ──────────────▶ 保持不变
|
||||
|
||||
|
||||
═══════════════ FAILED 保护 ═══════════════
|
||||
|
||||
[R8] NORMAL, NONE, FAILED (源节点)
|
||||
│
|
||||
└── E11e ──────────────────▶ 跳过,保持 [R8] 不变
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 (源节点) | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E11a**: CREATE_OK | R9 (MISSING) | data ≠ None ∧ IDResolver.resolve_and_validate() = OK | 源 → R6 (NORMAL); **新建**目标 → R14 | 建立绑定; 新节点 data = 已替换 ID 的副本, data_id = "" |
|
||||
| **E11b**: CREATE_DEP_FAIL | R9 (MISSING) | data ≠ None ∧ IDResolver.resolve_and_validate() = FAIL | R13 (DEPENDENCY_ERROR) | error = "创建时依赖 ID 未解析: ..." |
|
||||
| **E11c**: UPDATE_DIFF | R6/R7 (NORMAL, status≠FAILED) | 目标存在 ∧ 目标 data_id ≠ "" ∧ ID 解析 OK ∧ _needs_update() = True | 目标 → R18 (UPDATE, PENDING) | 目标: data 替换, error = None |
|
||||
| **E11d**: UPDATE_PRECOND_FAIL | R6/R7 (NORMAL, status≠FAILED) | 目标 data_id = "" (d1) 或 ID 解析失败 (d2) | 目标 → R22 (UPDATE, PRECONDITION_FAILED) | error = "目标缺少 data_id" 或 "依赖 ID 未解析" |
|
||||
| **E11e**: UPDATE_SKIP_FAILED | R8 (NORMAL, FAILED) | status = FAILED | R8 不变 | 保护上次的 error 和 FAILED 状态,不做任何修改 |
|
||||
|
||||
> **代码**: `strategy_ops/create_ops.py::add_create_action()` · `strategy_ops/update_ops.py::add_update_action()`
|
||||
|
||||
---
|
||||
|
||||
#### 📡 阶段 3:Sync(物理同步)
|
||||
|
||||
**状态转换图:**
|
||||
|
||||
```
|
||||
[R14] NORMAL, CREATE, PENDING [R18] NORMAL, UPDATE, PENDING
|
||||
│ │
|
||||
└───────────────┬───────────────────┘
|
||||
│
|
||||
├── E12 (API 成功) ──────▶ [R16] CREATE,SUCCESS / [R20] UPDATE,SUCCESS
|
||||
├── E13 (API 失败) ──────▶ [R17] CREATE,FAILED / [R21] UPDATE,FAILED
|
||||
├── E16 (Handler 跳过) ──▶ [R23] CREATE, SKIPPED
|
||||
├── E17 (Handler 降级) ──▶ [R6] NORMAL, NONE, PENDING (仅 UPDATE)
|
||||
│
|
||||
└── E14 (异步提交) ──────▶ [R15] CREATE,IN_PROGRESS / [R19] UPDATE,INP
|
||||
│
|
||||
├── (轮询成功) ──▶ [R16] / [R20] SUCCESS
|
||||
└── E15 (超时) ──▶ [R17] / [R21] FAILED
|
||||
```
|
||||
|
||||
**转换表:**
|
||||
|
||||
| 事件 | 起始状态 | 判断条件 (Guard) | 结束状态 | 副作用 |
|
||||
|------|---------|-----------------|---------|--------|
|
||||
| **E12**: SYNC_OK | R14 或 R18 | Handler API 返回 SUCCESS | R16 (CREATE) 或 R20 (UPDATE) | error → None; data_id 回填 (CREATE); origin_data 更新 (UPDATE) |
|
||||
| **E13**: SYNC_FAIL | R14 或 R18 | Handler API 返回 FAILED | R17 (CREATE) 或 R21 (UPDATE) | error = Handler 返回的错误信息 |
|
||||
| **E14**: SYNC_ASYNC | R14 或 R18 | Handler API 返回 IN_PROGRESS | R15 (CREATE) 或 R19 (UPDATE) | 记录 task_id, 进入轮询队列 |
|
||||
| **E15**: SYNC_TIMEOUT | R15 或 R19 | 轮询次数 > max_retries | R17 (CREATE) 或 R21 (UPDATE) | error = "Async task timeout after N seconds" |
|
||||
| **E16**: HANDLER_SKIP | R14 或 R18 | Handler API 返回 SKIPPED | R23 (CREATE,SKIPPED) | error → None |
|
||||
| **E17**: HANDLER_DOWNGRADE | R18 (仅 UPDATE) | Handler 运行时发现无实际变更字段 | R6 (NORMAL, NONE, PENDING) | action: UPDATE → NONE; 不提交 API; 统计列从 update 移入 none |
|
||||
|
||||
> **代码**: `BaseDataSource._handle_task_result()` · `_poll_async_tasks()` · `domain/*/api_handler.py`
|
||||
|
||||
---
|
||||
|
||||
## §4 终态分类与死胡同
|
||||
|
||||
### §4.1 终态分类
|
||||
|
||||
| 分类 | 状态 | (binding_status, action, status) | 语义 | 下一轮行为 |
|
||||
|------|------|------|------|---------|
|
||||
| ✅ 成功 | R16 | (NORMAL, CREATE, SUCCESS) | 创建成功 | →R2→bind→R7→update 检查 |
|
||||
| ✅ 成功 | R20 | (NORMAL, UPDATE, SUCCESS) | 更新成功 | →R2→bind→R7→update 检查 |
|
||||
| ❌ 失败 | R17 | (NORMAL, CREATE, FAILED) | 创建失败 | E02 zombie 判定→删除节点→对方回到 R9 重建 |
|
||||
| ❌ 失败 | R21 | (NORMAL, UPDATE, FAILED) | 更新失败 | →R3→bind→R8→FAILED 保护(E11e)→保持 |
|
||||
| 🔒 阻断 | R11 | (ABNORMAL, NONE, \*) | 数据损坏 | 每轮重新 bind 检查; 需人工修复数据 |
|
||||
| 🔒 阻断 | R12 | (WARNING, NONE, \*) | 多候选/对方异常 | 每轮重新 bind 检查; 需人工绑定或修复 |
|
||||
| 🔒 阻断 | R13 | (DEPENDENCY_ERROR, NONE, PENDING) | 依赖不满足 | 每轮重新检查依赖; 依赖修复后自动恢复 |
|
||||
| ⏭ 跳过 | R23 | (NORMAL, CREATE, SKIPPED) | Handler 跳过创建 | →R4→bind→R6→update 检查(无绑定则再 create) |
|
||||
| 🔄 异步 | R15 | (NORMAL, CREATE, IN\_PROGRESS) | 创建异步中 | 轮询直到 SUCCESS 或超时→FAILED |
|
||||
| 🔄 异步 | R19 | (NORMAL, UPDATE, IN\_PROGRESS) | 更新异步中 | 轮询直到 SUCCESS 或超时→FAILED |
|
||||
| 🔄 前置失败 | R22 | (NORMAL, UPDATE, PRECONDITION\_FAILED) | 前置条件不满足 | →R5→bind→R6/R7→update 重试 |
|
||||
|
||||
### §4.2 恢复路径
|
||||
|
||||
```
|
||||
R17 (CREATE, FAILED):
|
||||
持久化 → 下轮 E01 → 瞬态(UNCHECKED, CREATE, FAILED)
|
||||
→ E02: action=CREATE ∧ (status=FAILED ∨ data_id="") → 满足 zombie 条件
|
||||
→ 删除节点 + 解除绑定
|
||||
→ 对方节点回到 R9 (MISSING) → 重新进入 create 流程
|
||||
|
||||
R21 (UPDATE, FAILED):
|
||||
持久化 → 下轮 E01 → 瞬态(UNCHECKED, UPDATE, FAILED)
|
||||
→ E02: action=UPDATE ≠ CREATE → 非 zombie,存活
|
||||
→ E03: action → NONE → R3 (UNCHECKED, NONE, FAILED)
|
||||
→ bind → R8 (NORMAL, NONE, FAILED)
|
||||
→ E11e: FAILED 保护 → 跳过 update → 保持 R8
|
||||
⚠ 需人工清除 FAILED 才能恢复
|
||||
|
||||
R22 (UPDATE, PRECONDITION_FAILED):
|
||||
持久化 → 下轮 E01 → 瞬态(UNCHECKED, UPDATE, PRECONDITION_FAILED)
|
||||
→ E02: action=UPDATE ≠ CREATE → 非 zombie,存活
|
||||
→ E03: action → NONE → R5 (UNCHECKED, NONE, PRECONDITION_FAILED)
|
||||
→ bind → R6/R7 (NORMAL) → update 流程重试
|
||||
|
||||
R11 (ABNORMAL):
|
||||
每轮 E01 重置 → bind 重新检查
|
||||
→ 若数据被人工修复 → E04 → R6/R7/R8 (NORMAL)
|
||||
→ 若数据仍损坏 → 再次 R11
|
||||
|
||||
R12 (WARNING):
|
||||
每轮 E01 重置 → bind 重新检查
|
||||
→ 若人工建立了绑定 → E04 → R6/R7 (NORMAL)
|
||||
→ 若对方数据被修复 → E04 → R6/R7 (NORMAL)
|
||||
|
||||
R13 (DEPENDENCY_ERROR):
|
||||
每轮 E01 重置 → bind 重新检查依赖
|
||||
→ 依赖节点达到 NORMAL 且 data_id 非空后
|
||||
→ E07 通过 → 继续 auto_bind 或 create 流程
|
||||
```
|
||||
|
||||
### §4.3 FAILED 保护机制详解
|
||||
|
||||
FAILED 保护确保失败节点不会被后续流程静默覆盖,保留 error 信息供人工调查。
|
||||
|
||||
```
|
||||
进入条件:
|
||||
节点经过 bind 后为 R8 (NORMAL, NONE, FAILED)
|
||||
即: 绑定关系正常,但上一轮执行失败
|
||||
|
||||
保护行为:
|
||||
`strategy_ops/update_ops.py::add_update_action()` 中:
|
||||
if source.status == SyncStatus.FAILED:
|
||||
skip (→ 事件 E11e)
|
||||
结果: R8 原样保持 → 持久化 → 下一轮依然 R8
|
||||
|
||||
解除条件 (需人工介入):
|
||||
1. 清除 error 字段 (→ None)
|
||||
2. 将 status 改为 PENDING 或 SUCCESS
|
||||
3. 下轮 bind 后 → R6 或 R7 → 正常进入 update 流程
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §5 完备性分析
|
||||
|
||||
### §5.1 状态 × 事件矩阵
|
||||
|
||||
行 = 当前状态,列 = 可能触发的事件。`→Rx` = 转换到目标状态,`—` = 不可能触发。
|
||||
|
||||
| 状态 | E01 | E02 | E03 | E04/E05 | E06~E10 | E11a/b | E11c/d/e | E12~E17 |
|
||||
|------|-----|-----|-----|---------|---------|--------|----------|---------|
|
||||
| R1~R5 | — | — | — | →R6~R13 | — | — | — | — |
|
||||
| R6/R7 | →瞬态 | — | — | — | — | — | →R18/R22 | — |
|
||||
| R8 | →瞬态 | — | — | — | — | — | →R8(skip) | — |
|
||||
| R9 | →瞬态 | — | — | — | →R6/R11~R13 | →R6+R14/R13 | — | — |
|
||||
| R11~R13 | →瞬态 | — | — | — | — | — | — | — |
|
||||
| R14 | →瞬态 | — | — | — | — | — | — | →R15~R17/R23 |
|
||||
| R15 | →瞬态 | — | — | — | — | — | — | →R16/R17 |
|
||||
| R18 | →瞬态 | — | — | — | — | — | — | →R6/R19~R21/R23 |
|
||||
| R19 | →瞬态 | — | — | — | — | — | — | →R20/R21 |
|
||||
| R16/R17 | →瞬态 | — | — | — | — | — | — | — |
|
||||
| R20~R23 | →瞬态 | — | — | — | — | — | — | — |
|
||||
|
||||
> **读表方式**: 找到当前状态行和事件列组的交叉点,即可得到目标状态。`—` 表示该状态不可能触发该事件。
|
||||
|
||||
### §5.2 已知 GAP
|
||||
|
||||
| GAP | 描述 | 风险 | 建议 |
|
||||
|-----|------|------|------|
|
||||
| GAP-1 | `set_binding_status()` / `set_action()` / `set_status()` 是纯 setter,不验证转换合法性 | 中 | 加入前置断言:检查 (当前状态, 新状态) 是否匹配某条已知转换 |
|
||||
| GAP-2 | INV-1 ~ INV-10 未在代码中 assert | 中 | 每次 setter 调用后或阶段结束时断言所有不变量 |
|
||||
| GAP-3 | R22 (PRECONDITION\_FAILED) 节点下一轮行为路径需验证 | 低 | 已补充恢复路径: R22→E01→E03→R5→bind→R6/R7→update 重试 |
|
||||
| GAP-4 | Handler 降级 (E17) 后 status 残留为 PENDING 但 action 已清零 | 低 | 可考虑降级时同时重置 status 为 SUCCESS(当前保持 PENDING) |
|
||||
| GAP-5 | 物理同步后缺少整体一致性检查 (post-sync invariant check) | 低 | 在 `sync_all()` 结束后遍历所有节点验证 INV-1 ~ INV-10 |
|
||||
|
||||
---
|
||||
|
||||
## §6 引用
|
||||
|
||||
| 文档 | 路径 |
|
||||
|------|------|
|
||||
| 枚举定义 | `sync_system_new/common/types.py` |
|
||||
| 决策引擎 | `sync_system_new/sync_system/decision.py` |
|
||||
| 重置策略 | `sync_system_new/common/state_reset.py` |
|
||||
| 同步策略 | `sync_system_new/sync_system/strategy.py` |
|
||||
| 物理同步 | `sync_system_new/datasource/datasource.py` |
|
||||
| ID 解析 | `sync_system_new/sync_system/resolve_ids.py` |
|
||||
| 节点生命周期(叙事) | [节点生命周期状态转移](./节点生命周期状态转移.md) |
|
||||
@@ -0,0 +1,534 @@
|
||||
# 同步编排流程规范 (Pipeline Specification)
|
||||
|
||||
本文档定义了完整的同步编排流程,包括各阶段的职责、节点状态转换和检查点。
|
||||
|
||||
> **详细的状态定义和转换规则,请参考**: [STATE_DEFINITIONS.md](../sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
---
|
||||
|
||||
## 流程概览
|
||||
|
||||
同步系统的完整执行流程分为 5 个阶段:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 0: 初始化 (Initialization) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - 创建 Collection (Local/Remote) │
|
||||
│ - 创建 BindingManager │
|
||||
│ - 注册 SyncStrategy (各业务类型) │
|
||||
│ - 创建 DataSource (Local/Remote) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 1: 数据加载 (Data Loading) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 节点状态: binding_status=UNCHECKED, action=NONE, status=PENDING │
|
||||
│ - Persistence.load_nodes() → 从持久化恢复 │
|
||||
│ - DataSource.load_all() → 从数据源加载 │
|
||||
│ - BindingManager.load_bindings() → 加载绑定关系 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 2 & 3: 策略执行与同步 (按 node_type 顺序) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ For each node_type in sync_order: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 2.1 bind() → 绑定判定 │ │
|
||||
│ │ 2.2 create() → 设置 CREATE action │ │
|
||||
│ │ └─ 内联 ID 解析 + 前置检查 │ │
|
||||
│ │ 2.3 Commit Creates → 立即同步 CREATE 节点 │ │
|
||||
│ │ └─ DataSource.sync_all(poll_async=True) │ │
|
||||
│ │ 2.4 update() → 设置 UPDATE action │ │
|
||||
│ │ └─ 内联 ID 解析 + 前置检查 │ │
|
||||
│ │ 2.5 Commit Updates → 立即同步 UPDATE 节点 │ │
|
||||
│ │ └─ DataSource.sync_all(poll_async=True) │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 说明: │
|
||||
│ - 每个 node_type 完整同步后才处理下一个(保证依赖顺序) │
|
||||
│ - commit 操作内部包含异步轮询,无需独立轮询阶段 │
|
||||
│ - sync_all() 自动过滤 action=CREATE/UPDATE 的节点 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 4: 同步结果报告 (Summary Report) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - 打印同步结果摘要 │
|
||||
│ * 节点统计(按 action/status 分类) │
|
||||
│ * 绑定关系统计 │
|
||||
│ * 异常节点检查(data_id 缺失、绑定缺失等) │
|
||||
│ - 收集统计信息(成功/失败/残留问题) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Stage 5: 状态持久化 (State Persistence) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ - Collection.persist() → 保存节点状态 │
|
||||
│ - BindingManager.persist() → 保存绑定关系 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
【流程完成】
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 各阶段节点状态
|
||||
|
||||
### Stage 0: 初始化
|
||||
|
||||
**输出**: 所有组件实例化完成。
|
||||
|
||||
---
|
||||
|
||||
### Stage 1: 数据加载
|
||||
|
||||
**节点状态**:
|
||||
```python
|
||||
binding_status = BindingStatus.UNCHECKED # 未判定
|
||||
action = SyncAction.NONE # 无动作
|
||||
status = SyncStatus.PENDING # 待处理
|
||||
data_id = <从数据源加载> # 已有业务ID
|
||||
origin_data = <从数据源加载> # 原始数据快照
|
||||
data = <从数据源加载> # 当前数据
|
||||
depend_ids = <从数据源加载> # 依赖节点列表
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- `data_id` 在加载时**必定有值**(来自数据源)
|
||||
- 只有待创建的新节点 `data_id` 才可能为 ""(空字符串)
|
||||
- 从持久化恢复时应重置所有 `action` 为 `NONE`
|
||||
- `binding_status` 初始值是 `UNCHECKED`,不是 `None`
|
||||
|
||||
---
|
||||
|
||||
### Stage 2.1: Bind (状态判定)
|
||||
|
||||
**状态转换**: `binding_status: UNCHECKED → NORMAL/MISSING/ABNORMAL/WARNING/DEPENDENCY_ERROR`
|
||||
|
||||
**可能的结果状态**:
|
||||
|
||||
| 结果状态 | 含义 | 占比 |
|
||||
|---------|------|-----|
|
||||
| **NORMAL** | 有绑定,数据健康 | 大部分 |
|
||||
| **MISSING** | 无绑定,孤儿节点 | 少量 |
|
||||
| **ABNORMAL** | 有绑定,自身数据损坏 | 极少 |
|
||||
| **WARNING** | 有绑定,对方数据损坏 | 极少 |
|
||||
| **DEPENDENCY_ERROR** | 依赖未满足 | 少量 |
|
||||
|
||||
**详细规则**: 参考 [STATE_DEFINITIONS.md § 1-3](../sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
**补充约束**:
|
||||
- 若依赖节点 `binding_status = NORMAL` 但 `data_id` 为空(含 `status = FAILED`),视为依赖阻断。
|
||||
- 只要依赖节点已回填 `data_id`,即使其 `status = FAILED`,后续类型仍允许进入 Create/Update。
|
||||
- 自动绑定只在**业务键完整且唯一**时才尝试:
|
||||
- 若业务键字段缺失(如 `serial_number = null`),设置 `binding_status = WARNING`,并在 `node.error` 记录原因:`Auto-bind skipped: missing fields ...`。
|
||||
- 若同一业务键出现多对多/多对一,设置 `binding_status = WARNING`,并在 `node.error` 记录原因:`Auto-bind skipped: ambiguous candidates`。
|
||||
- 以上情况仅记录 **Warning**,不进行自动绑定。
|
||||
|
||||
---
|
||||
|
||||
### Stage 2.2: Create (孤儿处理)
|
||||
|
||||
**状态转换**: `action: NONE → CREATE` (对 MISSING 节点)
|
||||
|
||||
**补充约束**:
|
||||
- `binding_status = WARNING` 的节点不会进入 CREATE(`create()` 只查找 MISSING 节点)
|
||||
- 创建时会通过 `IDResolver.resolve_and_validate()` 二次验证依赖 ID,失败则设置 `DEPENDENCY_ERROR`
|
||||
|
||||
**副作用**:
|
||||
- 在对方 Collection 创建新节点
|
||||
- 新节点的 `binding_status = NORMAL, action = CREATE, data_id = ""`
|
||||
- 建立绑定记录
|
||||
- 原 MISSING 节点也变为 `NORMAL`
|
||||
|
||||
**示例**:
|
||||
```
|
||||
Before:
|
||||
local_node: binding_status=MISSING, action=NONE
|
||||
|
||||
After Create:
|
||||
local_node: binding_status=NORMAL, action=NONE
|
||||
remote_node (新建): binding_status=NORMAL, action=CREATE, data_id=""
|
||||
绑定记录: local_id ↔ remote_temp_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Stage 2.3: Update (差异同步)
|
||||
|
||||
**状态转换**: `action: NONE → UPDATE` (对 NORMAL 且有差异的节点)
|
||||
|
||||
**前提条件**:
|
||||
- `binding_status = NORMAL`
|
||||
- `status != FAILED`(保护上次失败的状态和错误信息)
|
||||
- `compute_diff()` 判定有差异
|
||||
- 配置的 `update_direction` 决定哪一方节点设置 UPDATE
|
||||
|
||||
**内联检查**:
|
||||
- 目标节点 `data_id` 为空 → `status = PRECONDITION_FAILED`
|
||||
- `IDResolver.resolve_and_validate()` 失败 → `status = PRECONDITION_FAILED`
|
||||
- Handler 校验后无实际变更字段 → `action` 降级为 `NONE`(不提交)
|
||||
|
||||
---
|
||||
|
||||
### Stage 2 & 3: 策略执行与同步
|
||||
|
||||
**执行顺序**: 按 `sync_order` 顺序逐个处理 node_type
|
||||
|
||||
**单个 node_type 的完整流程**:
|
||||
|
||||
```
|
||||
For node_type in sync_order:
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.1 Bind - 绑定判定 │
|
||||
│ - 设置 binding_status: NORMAL/MISSING/... │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.2 Create - 创建策略 │
|
||||
│ - 处理 MISSING 节点,设置 action=CREATE │
|
||||
│ - 内联 ID 解析验证 (resolve_and_validate) │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.3 Commit Creates - 立即同步 CREATE │
|
||||
│ - DataSource.sync_all(poll_async=True) │
|
||||
│ - 自动过滤 action=CREATE 的节点 │
|
||||
│ - 内部包含异步轮询(IN_PROGRESS→SUCCESS)│
|
||||
│ - ⭐ 执行 data_id 回填和绑定更新 │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.4 Update - 更新策略 │
|
||||
│ - 处理差异节点,设置 action=UPDATE │
|
||||
│ - 内联 ID 解析验证 + data_id 检查 │
|
||||
│ - FAILED 节点自动跳过 │
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 2.5 Commit Updates - 立即同步 UPDATE │
|
||||
│ - DataSource.sync_all(poll_async=True) │
|
||||
│ - 自动过滤 action=UPDATE 的节点 │
|
||||
│ - 内部包含异步轮询(IN_PROGRESS→SUCCESS)│
|
||||
└─────────────────────────────────────────────┘
|
||||
↓
|
||||
下一个 node_type
|
||||
```
|
||||
|
||||
**关键特性**:
|
||||
1. **按类型顺序**: 每个 node_type 完全同步后才处理下一个(保证依赖顺序)
|
||||
2. **立即提交**: create/update 后立即同步,不等待所有策略执行完
|
||||
3. **内置轮询**: `sync_all(poll_async=True)` 内部自动轮询异步任务
|
||||
4. **data_id 回填**: CREATE 成功后立即回填 data_id,下游依赖可用
|
||||
|
||||
**同步状态转换**:
|
||||
|
||||
**同步接口(一步式)**:
|
||||
```
|
||||
action=CREATE, API 成功 → status=SUCCESS, data_id=<远程ID>
|
||||
action=CREATE, API 失败 → status=FAILED, error=<错误信息>
|
||||
action=UPDATE, API 成功 → status=SUCCESS
|
||||
action=UPDATE, API 失败 → status=FAILED, error=<错误信息>
|
||||
action=NONE → status=PENDING (不执行)
|
||||
```
|
||||
|
||||
**异步接口(两步式,内置轮询)**:
|
||||
```
|
||||
action=CREATE, 提交成功 → status=IN_PROGRESS, task_id=<任务ID>
|
||||
status=IN_PROGRESS, 轮询中... → status=IN_PROGRESS (保持)
|
||||
status=IN_PROGRESS, 轮询成功 → status=SUCCESS, data_id=<远程ID>
|
||||
status=IN_PROGRESS, 轮询失败 → status=FAILED, error=<错误信息>
|
||||
status=IN_PROGRESS, 超时 → status=FAILED, error="Timeout"
|
||||
```
|
||||
|
||||
**关键副作用**(由 DataSource 在 sync_all 中执行):
|
||||
- CREATE 成功: `data_id` 从 "" 更新为远程分配的 ID,并回写 `data` 主键字段
|
||||
- CREATE 成功: 绑定记录从临时ID更新为真实ID
|
||||
- UPDATE 成功: `origin_data` 更新为当前 `data`
|
||||
- DELETE 成功: 移除绑定记录
|
||||
|
||||
**skip_sync 处理**:
|
||||
- 如果 `strategy.skip_sync = True`,跳过 create/update/commit 步骤
|
||||
- bind 步骤始终执行(用于状态判定)
|
||||
|
||||
**详细规则**: 参考 [STATE_DEFINITIONS.md § 5](../sync_system/STATE_DEFINITIONS.md)
|
||||
|
||||
---
|
||||
|
||||
### Stage 4: 同步结果报告
|
||||
|
||||
**目标**: 打印同步结果摘要,帮助用户了解同步情况
|
||||
|
||||
**报告内容**:
|
||||
1. **节点统计**:按 node_type 统计各种 action/status 的节点数量
|
||||
2. **绑定关系**:每个 node_type 的绑定记录数
|
||||
3. **异常检查**:扫描并报告异常情况:
|
||||
- CREATE 成功但 data_id 为空(DataSource 回填失败)
|
||||
- CREATE 成功但绑定记录缺失
|
||||
- UPDATE/CREATE 失败的节点及错误原因
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
================================================================================
|
||||
📊 Local Collection Summary
|
||||
================================================================================
|
||||
Node Type Bindings Create Update Delete None Total
|
||||
--------------------------------------------------------------------------------
|
||||
project 5/5 0(0/0/0) 2(2/0/0) 0(0/0/0) 3 5(5/0/0)
|
||||
contract 10/12 2(2/0/0) 5(5/0/0) 0(0/0/0) 5 12(12/0/0)
|
||||
```
|
||||
|
||||
**注意**: 此阶段不修改任何状态,仅作为信息展示。
|
||||
|
||||
---
|
||||
|
||||
### Stage 5: 状态持久化
|
||||
|
||||
**持久化内容**:
|
||||
- `binding_status`, `action`, `status` 的最终值
|
||||
- `data_id` (可能在 CREATE 后更新)
|
||||
- `error` (如果失败)
|
||||
- 绑定关系的完整映射
|
||||
|
||||
---
|
||||
|
||||
## 错误处理策略
|
||||
|
||||
| 阶段 | 失败类型 | 处理策略 |
|
||||
|------|---------|---------|
|
||||
| Stage 0 | 初始化失败 | **终止流程**,抛出异常 |
|
||||
| Stage 1 | 数据加载失败 | **终止流程**,抛出异常 |
|
||||
| Stage 2 & 3 | 代码异常 | **终止流程**,抛出异常 |
|
||||
| Stage 2: create/update 内联检查 | 依赖ID未解析、data_id缺失 | **继续流程**,节点标记为 DEPENDENCY_ERROR 或 PRECONDITION_FAILED |
|
||||
| Stage 2 & 3 | API 调用失败 | **继续流程**,标记节点 FAILED |
|
||||
| Stage 4 | - | 总是继续,仅作为报告 |
|
||||
| Stage 5 | 持久化失败 | **记录错误**,不影响内存状态 |
|
||||
|
||||
---
|
||||
|
||||
## 节点状态完整时间线
|
||||
|
||||
```
|
||||
┌──────────────┬─────────────┬────────┬────────┬─────────┐
|
||||
│ 阶段 │ binding_ │ action │ status │ data_id │
|
||||
│ │ status │ │ │ │
|
||||
├──────────────┼─────────────┼────────┼────────┼─────────┤
|
||||
│ 数据加载 │ UNCHECKED │ NONE │PENDING │ 已加载 │
|
||||
│ Bind │ NORMAL/... │ NONE │PENDING │ 已加载 │
|
||||
│ Create │ NORMAL │ CREATE │PENDING │ ""* │
|
||||
│ Commit Create│ NORMAL │ CREATE │SUCCESS │ 远程ID** │
|
||||
│ Update │ NORMAL │ UPDATE │PENDING │ 已加载 │
|
||||
│ Commit Update│ NORMAL │ UPDATE │SUCCESS │ 已加载 │
|
||||
└──────────────┴─────────────┴────────┴────────┴─────────┘
|
||||
|
||||
* 新创建的节点 data_id 初始为 ""
|
||||
** CREATE 成功后 data_id 立即更新为远程分配的ID,下游依赖可用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置驱动的流程控制
|
||||
|
||||
### 跳过某些阶段
|
||||
|
||||
```python
|
||||
pipeline_config = {
|
||||
"skip_bind": False, # 是否跳过 bind
|
||||
"skip_create": False, # 是否跳过 create
|
||||
"skip_update": False, # 是否跳过 update
|
||||
"skip_post_check": False, # 是否跳过同步后检查
|
||||
"fail_on_warning": False, # Pre-Check 时是否将 WARNING 视为失败
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**:`skip_pre_check` 已移除,原 `_pre_commit_check` 逻辑已内联到 create/update 方法中。
|
||||
```
|
||||
|
||||
### 策略预设应用
|
||||
|
||||
```python
|
||||
# 首次同步:启用自动绑定,双向创建
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("first_sync")
|
||||
|
||||
# 日常同步:仅推送更新
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("push_only")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 幂等性保证
|
||||
|
||||
**要求**: 同一个 Collection 的多次同步应该是幂等的。
|
||||
|
||||
**设计保证**:
|
||||
1. **Bind 阶段**: 基于绑定记录判定,已绑定节点不会重复绑定
|
||||
2. **Create 阶段**: 已有绑定的节点 (NORMAL) 不会重复创建
|
||||
3. **Update 阶段**: 基于 `compute_diff()` 判定,无差异则不执行
|
||||
4. **Sync 阶段**: `action=NONE` 的节点跳过执行
|
||||
|
||||
**前提条件**:
|
||||
- 绑定记录正确持久化
|
||||
- 节点的 `binding_status` 正确保存和加载
|
||||
- `compute_diff()` 逻辑准确
|
||||
|
||||
---
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 关键指标
|
||||
|
||||
| 指标 | 含义 | 阶段 |
|
||||
|------|------|-----|
|
||||
| `nodes_loaded` | 加载的节点总数 | Stage 1 |
|
||||
| `nodes_normal` | NORMAL 状态节点数 | Stage 2.1 |
|
||||
| `nodes_missing` | MISSING 状态节点数 | Stage 2.1 |
|
||||
| `nodes_abnormal` | ABNORMAL+WARNING 节点数 | Stage 2.1 |
|
||||
| `nodes_dep_error` | DEPENDENCY_ERROR 节点数 | Stage 2.1 |
|
||||
| `actions_create` | CREATE 动作节点数 | Stage 2.2 |
|
||||
| `actions_update` | UPDATE 动作节点数 | Stage 2.3 |
|
||||
| `sync_success` | 同步成功节点数 | Stage 3 |
|
||||
| `sync_failed` | 同步失败节点数 | Stage 3 |
|
||||
| `success_rate` | 成功率 (success/total) | Stage 4 |
|
||||
|
||||
### 日志级别
|
||||
|
||||
```
|
||||
INFO: 流程阶段切换、统计信息
|
||||
DEBUG: 节点级别的详细操作
|
||||
WARN: 检查发现的警告、同步失败
|
||||
ERROR: 检查发现的错误、致命异常
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [STATE_DEFINITIONS.md](../sync_system/STATE_DEFINITIONS.md) - 详细的状态定义和转换规则
|
||||
- [CHECK_SPEC.md](./CHECK_SPEC.md) - 检查点的实现细节和代码示例(可选)
|
||||
# 1. 持久化 Collection
|
||||
await local_collection.persist()
|
||||
await remote_collection.persist()
|
||||
|
||||
# 2. 持久化 Binding
|
||||
await binding_manager.persist()
|
||||
```
|
||||
|
||||
**持久化内容**:
|
||||
- 节点的 `binding_status`, `action`, `status`, `error`
|
||||
- 节点的 `data_id`(可能在 CREATE 后更新)
|
||||
- 绑定关系的完整映射
|
||||
|
||||
---
|
||||
|
||||
## 错误处理策略
|
||||
|
||||
### 各阶段的失败处理
|
||||
|
||||
| 阶段 | 失败原因示例 | 处理策略 |
|
||||
|------|------------|---------|
|
||||
| Stage 1: 数据加载 | 网络错误、文件缺失 | **终止流程**,抛出异常 |
|
||||
| Stage 2.1: Bind | 代码bug | **终止流程**,抛出异常 |
|
||||
| Stage 2.2-2.3: Create/Update | 代码bug | **终止流程**,抛出异常 |
|
||||
| Stage 2: create/update 内联检查 | 依赖ID未解析、data_id缺失 | **继续流程**,节点标记为 DEPENDENCY_ERROR 或 PRECONDITION_FAILED |
|
||||
| Stage 3: Physical Sync | API错误、权限不足 | **继续流程**,标记节点为 FAILED |
|
||||
| Stage 4: Post-Sync Check | 部分节点同步失败 | **继续流程**,打印警告 |
|
||||
| Stage 5: Persistence | 磁盘满、权限错误 | **记录错误**,但不影响内存状态 |
|
||||
|
||||
### 部分成功的处理
|
||||
|
||||
在 Stage 3 中,允许部分节点成功、部分失败:
|
||||
- 成功的节点: `status = SUCCESS`
|
||||
- 失败的节点: `status = FAILED`, `error = "错误信息"`
|
||||
|
||||
Post-Sync Check 会统计成功率并给出警告。
|
||||
|
||||
---
|
||||
|
||||
## 配置驱动的流程控制
|
||||
|
||||
### 跳过某些阶段
|
||||
|
||||
通过配置控制哪些阶段执行:
|
||||
|
||||
```python
|
||||
pipeline_config = {
|
||||
"skip_bind": False, # 是否跳过 bind
|
||||
"skip_create": False, # 是否跳过 create
|
||||
"skip_update": False, # 是否跳过 update
|
||||
"skip_post_check": False, # 是否跳过同步后检查
|
||||
"fail_on_warning": False, # 是否将 WARNING 也视为失败
|
||||
}
|
||||
```
|
||||
|
||||
### 策略预设应用
|
||||
|
||||
在 Stage 2 之前,可以应用策略预设:
|
||||
|
||||
```python
|
||||
# 首次同步:启用自动绑定,双向创建
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("first_sync")
|
||||
|
||||
# 日常同步:仅推送更新
|
||||
for strategy in strategies:
|
||||
strategy.apply_preset("push_only")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 关键指标
|
||||
|
||||
在各阶段收集以下指标:
|
||||
|
||||
| 指标 | 含义 |
|
||||
|------|------|
|
||||
| `nodes_loaded` | 加载的节点总数 |
|
||||
| `nodes_bound` | 成功绑定的节点数 |
|
||||
| `nodes_missing` | MISSING 状态的节点数 |
|
||||
| `nodes_abnormal` | ABNORMAL/WARNING 状态的节点数 |
|
||||
| `nodes_created` | CREATE 动作的节点数 |
|
||||
| `nodes_updated` | UPDATE 动作的节点数 |
|
||||
| `sync_success` | 同步成功的节点数 |
|
||||
| `sync_failed` | 同步失败的节点数 |
|
||||
| `errors_count` | 检查发现的 ERROR 数量 |
|
||||
| `warnings_count` | 检查发现的 WARNING 数量 |
|
||||
|
||||
### 日志级别
|
||||
|
||||
```
|
||||
INFO: 流程阶段切换、统计信息
|
||||
DEBUG: 节点级别的详细操作
|
||||
WARN: 检查发现的警告
|
||||
ERROR: 检查发现的错误、异常
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 幂等性保证
|
||||
|
||||
**要求**: 同一个 Collection 的多次同步应该是幂等的。
|
||||
|
||||
**设计保证**:
|
||||
1. **Bind 阶段**: 基于绑定记录判定状态,已绑定的节点不会重复绑定
|
||||
2. **Create 阶段**: 已有绑定的节点(NORMAL)不会重复创建
|
||||
3. **Update 阶段**: 基于 `compute_diff()` 判定,无差异则不执行
|
||||
4. **Sync 阶段**: DataSource 根据 `action` 执行,`action=NONE` 的节点跳过
|
||||
|
||||
**前提条件**:
|
||||
- Binding 记录正确持久化
|
||||
- 节点的 `binding_status` 正确保存和加载
|
||||
- `compute_diff()` 逻辑准确
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
详细的检查规范和状态转换规则,请参考:
|
||||
- [CHECK_SPEC.md](./CHECK_SPEC.md) - 检查点详细规范
|
||||
- [STATE_TRANSITIONS.md](./STATE_TRANSITIONS.md) - 状态转换表
|
||||
|
||||
@@ -0,0 +1,492 @@
|
||||
# 节点生命周期状态转移 (Node Lifecycle State Transitions)
|
||||
|
||||
本文档从一个**单节点视角**出发,完整描述一个 `SyncNode` 从诞生到持久化的全部状态变化。
|
||||
|
||||
> **代码映射**:
|
||||
> - 持久化重置:`sync_system_new/common/state_reset.py` → `NodeStateReset`
|
||||
> - 绑定判定:`sync_system_new/sync_system/decision.py` → `SyncDecisionEngine`
|
||||
> - 策略执行:`sync_system_new/sync_system/strategy.py` → `DefaultSyncStrategy`
|
||||
> - ID 解析:`sync_system_new/sync_system/resolve_ids.py` → `IDResolver`
|
||||
> - 物理同步:`sync_system_new/datasource/datasource.py` → `BaseDataSource`
|
||||
> - Handler 降级:`sync_system_new/domain/*/api_handler.py`
|
||||
|
||||
---
|
||||
|
||||
## 状态字段一览
|
||||
|
||||
| 字段 | 类型 | 含义 | 谁负责设置 |
|
||||
|------|------|------|-----------|
|
||||
| `binding_status` | BindingStatus | 绑定健康状态 | Strategy.bind() |
|
||||
| `action` | SyncAction | 待执行动作 | Strategy.create() / update() |
|
||||
| `status` | SyncStatus | 执行结果状态 | DataSource.sync_all() |
|
||||
| `data_id` | str | 业务主键ID | 数据加载 / DataSource 回填 |
|
||||
| `error` | str \| None | 错误信息 | 各阶段 |
|
||||
|
||||
---
|
||||
|
||||
## 完整生命周期
|
||||
|
||||
### 第一次运行(无持久化数据)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 节点尚不存在 │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
数据源加载 (Stage 1)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 节点诞生 │
|
||||
│ │
|
||||
│ binding_status = UNCHECKED ← Collection 创建节点时的初始值 │
|
||||
│ action = NONE │
|
||||
│ status = PENDING │
|
||||
│ data_id = "abc-123" ← 从数据源获取的业务主键 │
|
||||
│ data = {...} ← 从数据源获取的业务数据 │
|
||||
│ origin_data = {...} ← 同上,原始快照 │
|
||||
│ depend_ids = [] ← 空,待 bind 阶段填充 │
|
||||
│ error = None │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第二次及后续运行(有持久化数据)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 从持久化恢复(原始值) │
|
||||
│ │
|
||||
│ binding_status = NORMAL (上次值) │
|
||||
│ action = UPDATE (上次值) │
|
||||
│ status = SUCCESS (上次值) │
|
||||
│ data_id = "abc-123" │
|
||||
│ error = None (上次值) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
阶段1:加载时重置 (NodeStateReset)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 阶段1重置后 │
|
||||
│ │
|
||||
│ binding_status = UNCHECKED ← 重置(每次重新判定) │
|
||||
│ action = UPDATE ← 保留!(用于阶段2识别 CREATE 失败) │
|
||||
│ status = SUCCESS ← 保留!(不自动重置) │
|
||||
│ data_id = "abc-123" ← 不变 │
|
||||
│ data = None ← 重置(等待数据源覆盖) │
|
||||
│ origin_data = None ← 重置(等待数据源覆盖) │
|
||||
│ error = None ← 清空(避免上次错误干扰) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
阶段2:CREATE 僵尸清理
|
||||
(只影响 action=CREATE 且 status=FAILED 或 data_id="" 的节点)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 阶段2清理后(正常节点) │
|
||||
│ │
|
||||
│ action = NONE ← 全部重置为 NONE,准备进入策略阶段 │
|
||||
│ 其他字段不变 │
|
||||
│ │
|
||||
│ (若为 CREATE 僵尸节点:直接从 Collection 删除 + 解除绑定) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
数据源加载覆盖 (Stage 1 后半)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 数据源加载后 │
|
||||
│ │
|
||||
│ data = {...} ← 数据源最新数据覆盖 │
|
||||
│ origin_data = {...} ← 数据源最新数据覆盖 │
|
||||
│ 其他字段不变 │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bind 阶段状态转移 (Stage 2.1)
|
||||
|
||||
Bind 分三个子阶段顺序执行,每个子阶段只修改 `binding_status`。
|
||||
|
||||
### Phase 1: 核心状态判定
|
||||
|
||||
> **代码**:`strategy_ops/bind_ops.py::phase_core_state()` → `SyncDecisionEngine.determine_core_status()`
|
||||
|
||||
```
|
||||
输入:binding_status = UNCHECKED
|
||||
|
||||
┌─ 有绑定记录?
|
||||
│
|
||||
┌─────┤
|
||||
│ YES │
|
||||
│ └─── 本地数据 + 远程数据 都健康?
|
||||
│ │
|
||||
│ ┌────┴────┐
|
||||
│ │ YES │ NO
|
||||
│ ▼ ▼
|
||||
│ NORMAL WARNING / ABNORMAL
|
||||
│
|
||||
│ NO
|
||||
└──────────────► MISSING
|
||||
```
|
||||
|
||||
| 输入条件 | binding_status 输出 |
|
||||
|---------|-------------------|
|
||||
| 有绑定,双方数据健康 | **NORMAL** |
|
||||
| 有绑定,自身数据损坏 | **ABNORMAL** |
|
||||
| 有绑定,对方数据损坏 | **WARNING** |
|
||||
| 无绑定记录 | **MISSING** |
|
||||
|
||||
### Phase 2: 依赖检查
|
||||
|
||||
> **代码**:`strategy_ops/bind_ops.py::phase_dependency_check()` → `strategy_ops/bind_ops.py::check_dependencies_for_nodes()`
|
||||
|
||||
**仅处理 `binding_status = MISSING` 的节点**,其他状态跳过。
|
||||
|
||||
```
|
||||
输入:binding_status = MISSING
|
||||
|
||||
┌─ 有配置 depend_fields?
|
||||
│
|
||||
┌─────┤
|
||||
│ NO └──► 保持 MISSING(无依赖,直接通过)
|
||||
│
|
||||
│ YES ──► 逐一检查依赖节点:
|
||||
│ │
|
||||
│ ┌────┴────────────────────────┐
|
||||
│ │ 全部依赖节点: │
|
||||
│ │ - 存在? ✅ │
|
||||
│ │ - binding_status=NORMAL? ✅ │
|
||||
│ │ - data_id 非空? ✅ │
|
||||
│ └────┬────────────────────────┘
|
||||
│ │
|
||||
│ ┌────┴────┐
|
||||
│ │ 全通过 │ 任一失败
|
||||
│ ▼ ▼
|
||||
│ MISSING DEPENDENCY_ERROR
|
||||
│ + error = "依赖项不满足: ..."
|
||||
│ + depend_ids 已填充
|
||||
```
|
||||
|
||||
**副作用**:无论检查是否通过,都会填充 `node.depend_ids`。
|
||||
|
||||
### Phase 3: 自动绑定
|
||||
|
||||
> **代码**:`strategy_ops/bind_ops.py::phase_auto_binding()`
|
||||
|
||||
**仅处理 `binding_status = MISSING` 且依赖已通过的节点**。
|
||||
|
||||
```
|
||||
输入:binding_status = MISSING
|
||||
|
||||
auto_bind = False?
|
||||
└──► MISSING → WARNING("跳过自动绑定,无法确认是否需要创建")
|
||||
|
||||
auto_bind = True:
|
||||
│
|
||||
├─ 业务键字段缺失?
|
||||
│ └──► MISSING → WARNING("缺少业务键字段: ...")
|
||||
│
|
||||
├─ 业务键中 ID 字段解析失败?
|
||||
│ └──► MISSING → DEPENDENCY_ERROR("业务键中的ID字段解析失败")
|
||||
│
|
||||
├─ 去噪后 1:1 匹配?
|
||||
│ └──► MISSING → NORMAL(执行自动绑定,建立绑定记录)
|
||||
│
|
||||
├─ N:0(无远程匹配)?
|
||||
│ ├──► create_enabled = True → MISSING → NORMAL,并 spawn 目标 CREATE 节点(S06)
|
||||
│ └──► create_enabled = False → MISSING → WARNING(孤儿且不允许自动创建,需人工处理)
|
||||
│
|
||||
└─ N:M / 多对多 / 多对一?
|
||||
└──► MISSING → WARNING("存在多个候选节点,无法自动绑定")
|
||||
```
|
||||
|
||||
### Bind 阶段结束后可能的状态
|
||||
|
||||
| binding_status | 后续可执行的操作 |
|
||||
|---------------|----------------|
|
||||
| **NORMAL** | UPDATE(如有差异)|
|
||||
| **MISSING** | CREATE |
|
||||
| **ABNORMAL** | 无(需人工) |
|
||||
| **WARNING** | 无(阻止自动操作) |
|
||||
| **DEPENDENCY_ERROR** | 无(等待依赖修复) |
|
||||
|
||||
---
|
||||
|
||||
## Create 阶段状态转移 (Stage 2.2)
|
||||
|
||||
> **代码**:`create()` → `strategy_ops/create_ops.py::add_create_action()`
|
||||
|
||||
> **对齐说明(与状态机配置一致)**:
|
||||
> - create_prepare 的入口仍是源节点 `binding_status = MISSING`。
|
||||
> - 但当前配置下,`N:0 + create_enabled=true` 可以在自动绑定阶段直接把源节点转为 `NORMAL`,并 `emit spawn_target_node_state=S06`。
|
||||
> - 因此“触发创建”的入口有两条:
|
||||
> 1) auto_bind 分支(E08f)直接 spawn;
|
||||
> 2) create_prepare 分支(E09b)在 create 检查成功后 spawn。
|
||||
|
||||
**仅处理 `binding_status = MISSING` 的节点**。
|
||||
|
||||
```
|
||||
输入:源节点 binding_status = MISSING, action = NONE
|
||||
|
||||
┌─ 源节点数据为空?
|
||||
│ └──► 跳过,记录日志
|
||||
│
|
||||
├─ IDResolver.resolve_and_validate() 失败?
|
||||
│ └──► binding_status → DEPENDENCY_ERROR
|
||||
│ error = "创建时依赖 ID 未解析: ..."
|
||||
│
|
||||
└─ 成功 ──► 在目标 Collection 创建新节点
|
||||
│
|
||||
├─ 源节点:
|
||||
│ binding_status → NORMAL("从本地创建到远程")
|
||||
│ action 不变(仍为 NONE)
|
||||
│
|
||||
└─ 新建目标节点:
|
||||
binding_status = NORMAL
|
||||
action = CREATE
|
||||
status = PENDING
|
||||
data_id = ""(待远程返回)
|
||||
data = 已替换 ID 的数据副本
|
||||
│
|
||||
└─ 同时建立绑定记录:local_id ↔ remote_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commit Creates — 物理同步 (Stage 2.3)
|
||||
|
||||
> **代码**:`DataSource.sync_all()` → Handler.create()
|
||||
|
||||
```
|
||||
输入:action = CREATE, status = PENDING
|
||||
|
||||
┌─ Handler 执行 API 调用
|
||||
│
|
||||
├─ 同步 API 成功(200/201)
|
||||
│ └──► status → SUCCESS
|
||||
│ data_id = "remote-xyz"(远程分配的 ID 回填)
|
||||
│ data["id"] = "remote-xyz"(主键字段回写)
|
||||
│
|
||||
├─ 异步 API 提交成功(202)
|
||||
│ └──► status → IN_PROGRESS
|
||||
│ context.task_id = "task-xxx"
|
||||
│ │
|
||||
│ └─ 轮询结果:
|
||||
│ ├─ 成功 → status → SUCCESS, data_id 回填
|
||||
│ ├─ 失败 → status → FAILED, error = "..."
|
||||
│ └─ 超时 → status → FAILED, error = "Timeout"
|
||||
│
|
||||
└─ API 失败(4xx/5xx)
|
||||
└──► status → FAILED
|
||||
error = "远程操作失败: ..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Update 阶段状态转移 (Stage 2.4)
|
||||
|
||||
> **代码**:`update()` → `strategy_ops/update_ops.py::add_update_action()`
|
||||
|
||||
> **对齐说明**:图里的 `E12a` 从 `S01` 出发并不矛盾。`S01` 约束的是“源节点”有 `data_id`;
|
||||
> `E12a` 检查的是“目标节点”是否有 `data_id`(guard: `target_has_data_id=false`),两者不是同一个对象。
|
||||
|
||||
**过滤条件**:`binding_status = NORMAL` 且 `status != FAILED`
|
||||
|
||||
```
|
||||
输入:源节点 binding_status = NORMAL, action = NONE
|
||||
|
||||
┌─ status == FAILED?
|
||||
│ └──► 跳过(保护上次失败的状态和错误信息)
|
||||
│
|
||||
├─ 源节点数据为空?
|
||||
│ └──► 跳过
|
||||
│
|
||||
├─ 通过绑定找不到目标节点?
|
||||
│ └──► 跳过,记录日志
|
||||
│
|
||||
├─ 目标节点 data_id 为空?
|
||||
│ └──► 目标节点 status → PRECONDITION_FAILED
|
||||
│ ("目标节点缺少 data_id")
|
||||
│
|
||||
├─ IDResolver.resolve_and_validate() 失败?
|
||||
│ └──► 目标节点 action → UPDATE
|
||||
│ 目标节点 status → PRECONDITION_FAILED
|
||||
│ 目标节点 error = "依赖 ID 未解析: ..."
|
||||
│
|
||||
├─ _needs_update() 判定无差异?
|
||||
│ └──► 跳过(不设置 action)
|
||||
│
|
||||
└─ 有差异 ──► 更新目标节点:
|
||||
action → UPDATE
|
||||
status → PENDING
|
||||
data = 已替换 ID 的数据副本
|
||||
error = None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commit Updates — 物理同步 (Stage 2.5)
|
||||
|
||||
> **代码**:`DataSource.sync_all()` → Handler.update()
|
||||
|
||||
```
|
||||
输入:action = UPDATE, status = PENDING
|
||||
|
||||
┌─ Handler 构建 API 请求
|
||||
│
|
||||
├─ Handler 发现无实际变更字段
|
||||
│ └──► action → NONE(Handler 降级,不提交 API)
|
||||
│
|
||||
├─ 同步 API 成功(200)
|
||||
│ └──► status → SUCCESS
|
||||
│
|
||||
├─ 异步 API 提交成功(202)
|
||||
│ └──► status → IN_PROGRESS → (轮询)→ SUCCESS / FAILED
|
||||
│
|
||||
└─ API 失败
|
||||
└──► status → FAILED
|
||||
error = "远程操作失败: ..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 持久化阶段 (Stage 5)
|
||||
|
||||
```
|
||||
节点当前状态原样写入存储。
|
||||
|
||||
持久化字段:
|
||||
✅ node_id, data_id, data, origin_data
|
||||
✅ binding_status, action, status, error, context
|
||||
❌ depend_ids(不持久化,下次 bind 时从 data 实时计算)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 全景时间线表
|
||||
|
||||
下表展示**一个节点在典型场景中的状态变化**:
|
||||
|
||||
### 场景 A:首次创建(本地 → 远程)
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| 数据加载 | UNCHECKED | NONE | PENDING | "abc-123" | None |
|
||||
| bind phase1 | **MISSING** | NONE | PENDING | "abc-123" | None |
|
||||
| bind phase2 | MISSING | NONE | PENDING | "abc-123" | None |
|
||||
| bind phase3 | MISSING | NONE | PENDING | "abc-123" | None |
|
||||
| create | **NORMAL** | NONE | PENDING | "abc-123" | None |
|
||||
| _(新建远程节点)_ | NORMAL | **CREATE** | PENDING | **""** | None |
|
||||
| commit create | NORMAL | CREATE | **SUCCESS** | **"remote-456"** | None |
|
||||
| 持久化 | NORMAL | CREATE | SUCCESS | "remote-456" | None |
|
||||
|
||||
### 场景 B:日常更新
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| 持久化恢复 | NORMAL→**UNCHECKED** | CREATE→保留 | SUCCESS→保留 | "abc-123" | 清空 |
|
||||
| 阶段2 action重置 | UNCHECKED | **NONE** | SUCCESS | "abc-123" | None |
|
||||
| 数据源覆盖 | UNCHECKED | NONE | SUCCESS | "abc-123" | None |
|
||||
| bind phase1 | **NORMAL** | NONE | SUCCESS | "abc-123" | None |
|
||||
| update 检测差异 | NORMAL | NONE | SUCCESS | "abc-123" | None |
|
||||
| _(目标节点)_ | NORMAL | **UPDATE** | **PENDING** | "remote-456" | None |
|
||||
| commit update | NORMAL | UPDATE | **SUCCESS** | "remote-456" | None |
|
||||
|
||||
### 场景 C:依赖阻断
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| 数据加载 | UNCHECKED | NONE | PENDING | "contract-789" | None |
|
||||
| bind phase1 | **MISSING** | NONE | PENDING | "contract-789" | None |
|
||||
| bind phase2 | **DEPENDENCY_ERROR** | NONE | PENDING | "contract-789" | "依赖项不满足: project_id: 状态=dep_err" |
|
||||
| _(后续阶段不处理)_ | | | | | |
|
||||
| 持久化 | DEPENDENCY_ERROR | NONE | PENDING | "contract-789" | "依赖项不满足..." |
|
||||
|
||||
### 场景 D:CREATE 失败 → 下次自动恢复
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| **第 1 次运行** | | | | | |
|
||||
| create | NORMAL | CREATE | PENDING | "" | None |
|
||||
| commit create 失败 | NORMAL | CREATE | **FAILED** | "" | "远程操作失败: 500" |
|
||||
| 持久化 | NORMAL | CREATE | FAILED | "" | "远程操作失败: 500" |
|
||||
| **第 2 次运行** | | | | | |
|
||||
| 阶段1恢复 | **UNCHECKED** | CREATE | FAILED | "" | **None** |
|
||||
| 阶段2僵尸清理 | _(节点被删除,绑定被解除)_ | | | | |
|
||||
| 数据源重新加载 | UNCHECKED | NONE | PENDING | "" → 新 node_id | None |
|
||||
| bind → create | 重新走首次创建流程 | | | | |
|
||||
|
||||
### 场景 E:UPDATE 失败 → 保留供人工处理
|
||||
|
||||
| 阶段 | binding_status | action | status | data_id | error |
|
||||
|------|---------------|--------|--------|---------|-------|
|
||||
| **第 1 次运行** | | | | | |
|
||||
| update | NORMAL | UPDATE | PENDING | "remote-456" | None |
|
||||
| commit update 失败 | NORMAL | UPDATE | **FAILED** | "remote-456" | "403 Forbidden" |
|
||||
| 持久化 | NORMAL | UPDATE | FAILED | "remote-456" | "403 Forbidden" |
|
||||
| **第 2 次运行** | | | | | |
|
||||
| 阶段1恢复 | UNCHECKED | UPDATE | FAILED | "remote-456" | None |
|
||||
| 阶段2 action重置 | UNCHECKED | **NONE** | **FAILED** | "remote-456" | None |
|
||||
| bind | NORMAL | NONE | FAILED | "remote-456" | None |
|
||||
| update 跳过 | _(status=FAILED,自动跳过)_ | | | | |
|
||||
| 持久化 | NORMAL | NONE | FAILED | "remote-456" | None |
|
||||
| _(需人工重置 status 后才能重新更新)_ | | | | | |
|
||||
|
||||
---
|
||||
|
||||
## 状态转换合法性约束
|
||||
|
||||
### binding_status 允许的转换
|
||||
|
||||
```
|
||||
UNCHECKED → NORMAL (核心判定: 有绑定且健康)
|
||||
UNCHECKED → MISSING (核心判定: 无绑定记录)
|
||||
UNCHECKED → ABNORMAL (核心判定: 自身数据损坏)
|
||||
UNCHECKED → WARNING (核心判定: 对方数据损坏)
|
||||
|
||||
MISSING → DEPENDENCY_ERROR (依赖检查: 父节点不满足)
|
||||
MISSING → WARNING (自动绑定: 业务键缺失 / 多候选 / auto_bind=False)
|
||||
MISSING → DEPENDENCY_ERROR (自动绑定: ID 字段解析失败)
|
||||
MISSING → NORMAL (自动绑定: 1:1 成功)
|
||||
MISSING → NORMAL (create: 源节点创建成功后)
|
||||
MISSING → DEPENDENCY_ERROR (create: ID 解析失败)
|
||||
```
|
||||
|
||||
> **注意**:当前 `SyncNode.set_binding_status()` 不做转换合法性校验【未实现】。
|
||||
|
||||
### action 允许的转换
|
||||
|
||||
```
|
||||
NONE → CREATE (create: 新建目标节点)
|
||||
NONE → UPDATE (update: 检测到差异)
|
||||
UPDATE → NONE (Handler 降级: 实际无变更字段)
|
||||
```
|
||||
|
||||
### status 允许的转换
|
||||
|
||||
```
|
||||
PENDING → IN_PROGRESS (DataSource: 异步提交成功)
|
||||
PENDING → SUCCESS (DataSource: 同步执行成功)
|
||||
PENDING → FAILED (DataSource: 执行失败)
|
||||
PENDING → SKIPPED (DataSource: 被跳过)
|
||||
(常见于 CREATE/UPDATE:Handler 返回 SKIPPED(无可执行操作/业务条件不满足),对应状态机里的 E19→S13 或 E20→S14)
|
||||
PENDING → PRECONDITION_FAILED (Strategy: 前置条件不满足)
|
||||
IN_PROGRESS → SUCCESS (DataSource: 异步轮询成功)
|
||||
IN_PROGRESS → FAILED (DataSource: 异步轮询失败/超时)
|
||||
```
|
||||
|
||||
> **注意**:当前 `SyncNode.set_status()` 不做转换合法性校验【未实现】。
|
||||
|
||||
---
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [状态定义规范](./状态定义规范.md) — 状态枚举和判定规则
|
||||
- [持久化与人工介入规范](./持久化与人工介入规范.md) — 持久化重置策略
|
||||
- [编排流程规范](./编排流程规范.md) — Pipeline 阶段定义
|
||||
- [架构分层设计](./架构分层设计.md) — 各层职责
|
||||
- [node_id_data_id_lifecycle](./node_id_data_id_lifecycle.md) — ID 生命周期
|
||||
@@ -0,0 +1,11 @@
|
||||
# 同步系统重构目标
|
||||
|
||||
## 范围
|
||||
- 在 `sync_state_machine/` 下实现新状态机运行时,不改 `sync_system_new/` 现有实现。
|
||||
- 第一阶段聚焦 JSONL 路径,API 路径后续接入。
|
||||
|
||||
## 成功标准
|
||||
- 状态机配置可独立校验与出图。
|
||||
- 运行时可根据事件与上下文输出迁移决策。
|
||||
- 自动化测试可覆盖所有事件(E00~E20)并统计状态覆盖。
|
||||
- domain 业务层不直接改状态,状态变更由状态机输出驱动。
|
||||
@@ -0,0 +1,15 @@
|
||||
# 迁移映射
|
||||
|
||||
## 旧 -> 新
|
||||
- `sync_system_new/state_machine/*` -> `sync_state_machine/config|tools/*`
|
||||
- `strategy.py` 决策逻辑 -> `sync_state_machine/engine/* + sync_state_machine/sync_system/strategy.py`
|
||||
- `datasource.py` 状态写回 -> `sync_state_machine/datasource/datasource.py`
|
||||
- bind/create/update 事件驱动 -> `sync_state_machine/sync_system/strategy.py` 直接 dispatch(无桥接层)
|
||||
|
||||
## 不变项
|
||||
- `sync_system_new/domain/*` 业务处理逻辑保持不动。
|
||||
- `schemas/`、`filtered_datasource/` 不修改。
|
||||
|
||||
## 目录差异说明
|
||||
- `sync_state_machine/adapters/` 已移除,避免“新目录实现 + 适配桥接”双轨并存。
|
||||
- 状态机配置、执行、测试均在 `sync_state_machine` 内闭环。
|
||||
@@ -0,0 +1,454 @@
|
||||
# 自动测试说明
|
||||
|
||||
## 1. 目标
|
||||
|
||||
这套测试只做一件事:
|
||||
|
||||
- 用固定配置初始化测试环境;
|
||||
- 一键运行测试;
|
||||
- 验证同步系统能不能完成一轮正常同步;
|
||||
- 验证常见的更新接口能不能工作;
|
||||
- 能把问题大致分成三类:数据问题、推送系统问题、后端接口问题。
|
||||
|
||||
不追求把所有情况都测完,也不追求覆盖所有脏数据。测试深度控制在:
|
||||
|
||||
- 能跑通一次正常流程;
|
||||
- 能验证一批关键 update;
|
||||
- 能处理一些基本异常;
|
||||
- 每轮都能留下清楚的报告,供下一轮继续改。
|
||||
|
||||
## 2. 测试系统的组成
|
||||
|
||||
测试系统由 4 部分组成:
|
||||
|
||||
1. **测试配置**
|
||||
2. **初始化脚本**
|
||||
3. **按 domain 拆分的用例**
|
||||
4. **统一运行脚本**
|
||||
|
||||
只要把这 4 部分准备好,后面就应该做到:**运行一个脚本,就自动完成初始化、执行、分析、出报告。**
|
||||
|
||||
### 当前已落地的文件
|
||||
|
||||
目前已经先实现了一版最小骨架:
|
||||
|
||||
- 测试总配置:[tests/fixtures/auto_sync/auto_test_config.yaml](tests/fixtures/auto_sync/auto_test_config.yaml)
|
||||
- 流水线测试配置:[run_profiles/jsonl_to_api.test.yaml](run_profiles/jsonl_to_api.test.yaml)
|
||||
- 初始化脚本:[scripts/auto_test_init.py](scripts/auto_test_init.py)
|
||||
- 统一运行脚本:[scripts/run_auto_test.py](scripts/run_auto_test.py)
|
||||
- 公共工具:[scripts/auto_test_lib.py](scripts/auto_test_lib.py)
|
||||
- 第一个 domain 用例:[tests/fixtures/auto_sync/domains/contract.yaml](tests/fixtures/auto_sync/domains/contract.yaml)
|
||||
|
||||
## 3. 配置管理
|
||||
|
||||
测试环境必须基于配置初始化,不能靠手工改路径。
|
||||
|
||||
配置里至少要能定义这些内容:
|
||||
|
||||
- 后端代码目录;
|
||||
- 后端启动命令;
|
||||
- 后端恢复数据库命令;
|
||||
- 测试使用的数据库名;
|
||||
- CouchDB 连接信息;
|
||||
- 本地同步状态数据库路径;
|
||||
- 基础种子数据目录;
|
||||
- 同步测试数据目录;
|
||||
- 临时测试数据目录;
|
||||
- 同步系统运行配置文件路径。
|
||||
|
||||
建议单独准备一个测试配置,例如:
|
||||
|
||||
- `run_profiles/jsonl_to_api.test.yaml`
|
||||
- `docs/auto_test_spec` 中再约定测试总配置文件
|
||||
|
||||
### 数据目录分工
|
||||
|
||||
测试里至少有 3 类数据目录:
|
||||
|
||||
1. **基础种子数据**
|
||||
- 用来恢复后端里那些不能通过同步创建的数据。
|
||||
- 例如:`company`、`project`、`design_doc`。
|
||||
- 这类数据先进入后端数据库,给后续同步提供依赖。
|
||||
|
||||
2. **同步测试数据**
|
||||
- 用来测试可创建、可更新的业务数据。
|
||||
- 例如合同、结算、施工任务等。
|
||||
|
||||
3. **临时运行目录**
|
||||
- 每次测试前,把测试数据复制到这里。
|
||||
- 后续每一轮如果要改数据,也只改这里,不改原始测试集。
|
||||
|
||||
## 4. 初始化方式
|
||||
|
||||
初始化必须自动完成,不能再靠手工执行几条命令。
|
||||
|
||||
目标流程如下:
|
||||
|
||||
1. 读取测试配置;
|
||||
2. 如有旧测试数据库,先自动删除;
|
||||
3. 自动删除本地同步状态数据库;
|
||||
4. 自动执行后端的数据库恢复命令,导入基础种子数据;
|
||||
5. 自动启动后端;
|
||||
6. 自动等待后端 ready;
|
||||
7. 自动准备临时测试目录;
|
||||
8. 开始跑测试。
|
||||
|
||||
### 运行后的要求
|
||||
|
||||
- **测试跑完以后,数据库保留**,方便查看结果;
|
||||
- **下次再运行时,再自动清空旧库并重建**;
|
||||
- 不要求每次结束自动销毁环境。
|
||||
|
||||
## 5. 运行方式
|
||||
|
||||
不强制使用 `pytest`。
|
||||
|
||||
当前更适合的方式是:
|
||||
|
||||
- 用一个主脚本统一运行全部流程;
|
||||
- domain 用例由脚本按顺序调度;
|
||||
- 每个 domain 可以包含多轮 pipeline;
|
||||
- 每轮的输入数据和检查点都由脚本控制。
|
||||
|
||||
也就是:
|
||||
|
||||
- `测试配置 + 初始化脚本 + 分 domain 的用例 + 一个完整运行脚本`
|
||||
|
||||
## 6. 测试轮次
|
||||
|
||||
一次完整测试,允许分成多轮 pipeline。
|
||||
|
||||
典型做法:
|
||||
|
||||
### 第 1 轮:初始化后首次同步
|
||||
|
||||
目的:
|
||||
|
||||
- 验证基础依赖准备正确;
|
||||
- 验证 create 流程能跑通;
|
||||
- 验证绑定关系是否正常。
|
||||
|
||||
### 第 2 轮:在临时目录修改部分数据后再次同步
|
||||
|
||||
目的:
|
||||
|
||||
- 验证 update 接口;
|
||||
- 验证哪些数据应该更新;
|
||||
- 验证哪些数据应该保持不动。
|
||||
|
||||
### 第 3 轮:补充少量基本异常场景
|
||||
|
||||
目的:
|
||||
|
||||
- 验证系统遇到常见错误时能不能给出清楚结果;
|
||||
- 验证错误是否能定位到数据、推送系统或后端。
|
||||
|
||||
不要求无限轮次,也不要求复杂压力测试。
|
||||
|
||||
## 7. Domain 用例怎么设计
|
||||
|
||||
每个 domain 单独设计用例,例如:
|
||||
|
||||
- `company`
|
||||
- `project`
|
||||
- `contract`
|
||||
- `supplier`
|
||||
- `construction_task`
|
||||
- `contract_settlement`
|
||||
|
||||
但不是所有 domain 都从创建开始测。
|
||||
|
||||
要根据业务真实情况决定:
|
||||
|
||||
- 哪些 domain 只能作为基础种子存在;
|
||||
- 哪些 domain 可以通过同步创建;
|
||||
- 哪些 domain 要重点测 update。
|
||||
|
||||
### Domain 用例必须写清楚的内容
|
||||
|
||||
每个 domain 的用例说明都要先写文字,再写代码。文字说明必须经过你审定。
|
||||
|
||||
每组用例至少写清楚:
|
||||
|
||||
1. 这个 domain 的前置依赖是什么;
|
||||
2. 这个 domain 本轮准备哪些测试数据;
|
||||
3. 第几轮会创建哪些记录;
|
||||
4. 第几轮会修改哪些字段;
|
||||
5. 预期通过什么方式判断结果;
|
||||
6. 这个用例主要想识别哪类问题。
|
||||
|
||||
## 8. Domain 用例的测试原则
|
||||
|
||||
### 原则 1:优先覆盖大部分接口
|
||||
|
||||
目标不是追求完美覆盖,而是尽量覆盖大部分 create / update 接口,尤其是 update。
|
||||
|
||||
### 原则 2:只测明确的业务关系
|
||||
|
||||
用例里的依赖关系必须有文字说明,不能边跑边猜。
|
||||
|
||||
### 原则 3:可以通过改数据来构造用例
|
||||
|
||||
允许通过修改临时目录里的数据来构造 update 场景。
|
||||
|
||||
### 原则 4:判断结果不能只看日志
|
||||
|
||||
要结合下面几类证据一起判断:
|
||||
|
||||
- 日志;
|
||||
- collection 中的数据;
|
||||
- 持久化数据库中的结果;
|
||||
- 绑定记录;
|
||||
- 同步状态数据库。
|
||||
|
||||
### 原则 5:用例要能分出问题归属
|
||||
|
||||
每个用例都应该尽量帮助判断问题属于:
|
||||
|
||||
- 测试数据问题;
|
||||
- 推送系统问题;
|
||||
- 后端接口逻辑问题。
|
||||
|
||||
## 9. 建议的用例层次
|
||||
|
||||
每个 domain 的用例,优先按下面 4 类来补:
|
||||
|
||||
1. **正常创建**
|
||||
2. **正常更新**
|
||||
3. **关键绑定关系检查**
|
||||
4. **基本异常检查**
|
||||
|
||||
这里的“基本异常”只做常见的、对当前系统最有价值的,例如:
|
||||
|
||||
- 缺少依赖;
|
||||
- 关键字段不合法;
|
||||
- 远端返回明确错误;
|
||||
- 本地状态和远端状态不一致。
|
||||
|
||||
## 10. 运行脚本应该负责什么
|
||||
|
||||
统一运行脚本应负责:
|
||||
|
||||
1. 读取测试配置;
|
||||
2. 清空旧测试环境;
|
||||
3. 初始化后端数据库;
|
||||
4. 启动后端并等待可用;
|
||||
5. 准备临时测试数据;
|
||||
6. 按 domain 顺序执行各轮用例;
|
||||
7. 每轮运行 pipeline;
|
||||
8. 收集结果;
|
||||
9. 输出报告。
|
||||
|
||||
## 11. 测试报告要求
|
||||
|
||||
每轮都要有清晰报告,给下一轮继续优化使用。
|
||||
|
||||
报告至少包含:
|
||||
|
||||
- 测试时间;
|
||||
- 使用的配置;
|
||||
- 运行了哪些 domain;
|
||||
- 每个 domain 跑了几轮;
|
||||
- 每轮改了哪些数据;
|
||||
- 每轮成功 / 失败统计;
|
||||
- 失败样本;
|
||||
- 问题分类:数据 / 推送系统 / 后端;
|
||||
- 下一轮建议。
|
||||
|
||||
## 12. 当前结论
|
||||
|
||||
当前最合适的方案不是全量自动化,也不是一次性测完所有东西。
|
||||
|
||||
而是:
|
||||
|
||||
- 先做一套固定配置的测试环境;
|
||||
- 用一个脚本跑完整个流程;
|
||||
- 从少量 but 关键的 domain 开始;
|
||||
- 每个 domain 先把 create 和主要 update 跑通;
|
||||
- 每轮都留下明确报告;
|
||||
- 再逐步扩展。
|
||||
|
||||
这样更容易维护,也更适合后续让 Agent 按计划继续写代码。
|
||||
|
||||
## 13. 当前执行计划(2026-03-07)
|
||||
|
||||
当前轮次先处理两类目标:
|
||||
|
||||
1. `project_detail_data`
|
||||
- 继续确认可按统一 `project_detail_data` 语义验证的 key 与相关 update 接口在测试报告中可见、可追踪;
|
||||
- 重点检查它与后续 project 级 domain 连跑时是否污染状态。
|
||||
- 当前水电项目下,`production` 先不混入这组统一回归:后端已确认该接口会直接更新 `project` 字段,但不保证创建/更新可轮询的 `project_detail_data.production` 记录;后续待业务确认后再单列测试方案。
|
||||
|
||||
2. 剩余 domain
|
||||
- 当前优先处理:`contract_settlement_detail`、`personnel`、`personnel_detail`
|
||||
- 已完成并保持回归:`preparation`、`production`、`contract`、`contract_settlement`、`construction_task`、`construction_task_detail`、`material`、`material_detail`
|
||||
- 之后再继续:`units`、`contract_change`、`lar`、`lar_change`
|
||||
|
||||
本轮执行顺序:
|
||||
|
||||
1. 先补齐文字测试计划;
|
||||
2. 再修改测试脚本与 `tests/` 下测试数据;
|
||||
3. 逐个 domain 跑通;
|
||||
4. 最后回到整套自动测试顺序验证全量可跑通。
|
||||
|
||||
### 本轮强约束
|
||||
|
||||
- **禁止修改 `schemas/` 下任何文件。**
|
||||
- 不允许为了让测试通过而绕过 schema 校验。
|
||||
- 如果问题根因是后端接口/后端返回/后端数据模型不一致,应直接在报告里暴露并记录,不擅自改 schema。
|
||||
- 只有在确认是后端错误并得到明确指示后,才讨论是否调整类型定义。
|
||||
|
||||
### 本轮排查重点
|
||||
|
||||
1. `project_detail_data` 单跑已基本可用,但要继续验证与 `preparation`、`production` 连跑时是否造成绑定或状态污染;
|
||||
2. `preparation`、`production` 当前更像是“整套顺序执行时失败、单独执行可通过”的问题,优先检查运行顺序、临时数据、持久化状态和绑定残留;
|
||||
3. 其余 domain 按“先单 domain 跑通,再放回全量顺序”推进;
|
||||
- 当前先按 `contract_settlement_detail -> personnel -> personnel_detail` 顺序落地;
|
||||
4. 每修完一个 domain,都要保证报告中能看出本轮覆盖内容、绑定结果、字段变化和失败归因。
|
||||
5. 对 `project_detail_data.production`,禁止再用“接口没报错就直接记成功”的短路逻辑掩盖真实语义;当前阶段直接绕过该 key 的统一回归,保留差异说明。
|
||||
|
||||
## 14. 大规模测试方法:按轮迭代,而不是一次堆上下文
|
||||
|
||||
大规模测试的目标不是“把所有失败细节一次讲完”,而是:
|
||||
|
||||
- 每一轮只有一个清晰基线;
|
||||
- 每一轮只记录少量必须保留的信息;
|
||||
- 每一轮都能看到总计变化;
|
||||
- 每一轮都能区分“新问题、已修复问题、遗留问题”。
|
||||
|
||||
当前推荐固定采用 **单 domain 验证 + 全量聚合回归** 的两层节奏。
|
||||
|
||||
### 14.1 固定节奏
|
||||
|
||||
每一轮都按下面顺序执行:
|
||||
|
||||
1. **选定本轮目标**
|
||||
- 只选 1 个主问题,或者 1 组同类问题。
|
||||
- 例如:
|
||||
- 一个 domain 的 update 接口失败;
|
||||
- 一组共享 helper 导致的脚本设计问题;
|
||||
- 一类后端读写不一致问题。
|
||||
|
||||
2. **先单 domain 复现**
|
||||
- 用 [scripts/run_auto_test.py](scripts/run_auto_test.py) 只跑目标 domain。
|
||||
- 目的不是求“全绿”,而是先确认问题是否稳定复现。
|
||||
|
||||
3. **定位并修复一类根因**
|
||||
- 如果是测试脚本问题,就只修脚本;
|
||||
- 如果是后端问题,就在报告里明确标注为后端;
|
||||
- 如果是数据问题,就保留失败,不用 fallback 掩盖。
|
||||
|
||||
4. **回跑目标 domain**
|
||||
- 只看本 domain 是否改善;
|
||||
- 记录这轮减少了多少失败 case。
|
||||
|
||||
5. **再跑聚合回归**
|
||||
- 用 [scripts/run_auto_test_all_domains.py](scripts/run_auto_test_all_domains.py) 执行全量聚合;
|
||||
- 当前聚合模式是“**每个 domain 独立初始化并单独执行**”,用于避免跨 domain 状态污染。
|
||||
|
||||
6. **输出轮次结论**
|
||||
- 只保留:
|
||||
- 总 case 数;
|
||||
- 通过 / 失败数;
|
||||
- 新增失败;
|
||||
- 已修复失败;
|
||||
- 遗留失败;
|
||||
- 每个遗留失败的归因分类。
|
||||
|
||||
### 14.2 每轮只保留 4 份信息
|
||||
|
||||
为了避免上下文失控,每轮总结时只保留下面 4 份信息:
|
||||
|
||||
1. **总计快照**
|
||||
- `total_domains`
|
||||
- `passed_domains`
|
||||
- `failed_domains`
|
||||
- `total_cases`
|
||||
- `passed_cases`
|
||||
- `failed_cases`
|
||||
|
||||
2. **变化清单**
|
||||
- 本轮修复了哪些 case;
|
||||
- 本轮新增了哪些 case;
|
||||
- 哪些 case 没变化。
|
||||
|
||||
3. **失败分类表**
|
||||
- `script_design`:脚本设计 / 运行配置 / 断言策略问题;
|
||||
- `push_system`:状态机、绑定、依赖、持久化、推送链路问题;
|
||||
- `backend`:后端接口、后端读写模型、后端返回值问题;
|
||||
- `data`:测试数据不满足前置条件或数据本身不合法;
|
||||
- `flaky`:暂时只在聚合中出现、单跑不能稳定复现的问题。
|
||||
|
||||
4. **下一轮唯一目标**
|
||||
- 下一轮最多列 1~3 个目标;
|
||||
- 不把所有猜测都带到下一轮。
|
||||
|
||||
### 14.3 轮次汇总格式
|
||||
|
||||
每轮报告建议固定成下面的结构:
|
||||
|
||||
1. **Round N 总计**
|
||||
2. **与 Round N-1 对比**
|
||||
3. **本轮修复**
|
||||
4. **本轮新增**
|
||||
5. **遗留问题分类**
|
||||
6. **下一轮目标**
|
||||
|
||||
建议直接从聚合报告的 `summary.json` 中抽取总计,避免手工整理时带入过多细节。
|
||||
|
||||
### 14.4 建议的对比口径
|
||||
|
||||
比较两轮结果时,统一只按 `domain::round_name` 比较,不按日志文本比较。
|
||||
|
||||
也就是把每个 case 视为一个稳定键,例如:
|
||||
|
||||
- `project::round_2_base_info_update`
|
||||
- `project::round_3_investment_update`
|
||||
- `material_detail::round_2_update`
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
- 总数稳定;
|
||||
- 对比简单;
|
||||
- 很容易看出某个 case 是“由失败转通过”,还是“仍然失败”。
|
||||
|
||||
### 14.5 建议的推进策略
|
||||
|
||||
对于 10+ domain、数十个 case 的回归,建议始终按下面方式推进:
|
||||
|
||||
1. **先消灭稳定复现的单点失败**
|
||||
- 先修能稳定复现的问题,不先追偶发问题。
|
||||
|
||||
2. **再处理共享根因**
|
||||
- 如果多个 domain 共用同一个 helper、同一个运行配置、同一种绑定策略,优先处理这一层。
|
||||
|
||||
3. **最后单列 flaky**
|
||||
- 聚合里偶发失败、单跑通过的问题,不直接混入主结论;
|
||||
- 先标成 `flaky`,待重复出现后再升级处理。
|
||||
|
||||
### 14.6 当前这套系统中的实际判定方法
|
||||
|
||||
当前推荐把问题按下面顺序判定:
|
||||
|
||||
1. **先看单 domain 是否稳定失败**
|
||||
- 如果单跑失败,优先查该 domain 自身脚本、数据、后端接口。
|
||||
|
||||
2. **再看聚合回归是否额外引入失败**
|
||||
- 如果单跑通过、聚合失败,优先怀疑:
|
||||
- 运行顺序;
|
||||
- 环境残留;
|
||||
- 报告聚合方式;
|
||||
- 偶发后端错误。
|
||||
|
||||
3. **最后看后端是否写了但读不出来**
|
||||
- 如果 update 接口已命中,但回读字段缺失或不一致,要明确归类为 `backend`,而不是继续修改测试脚本绕过。
|
||||
|
||||
### 14.7 本文档要求的轮次目标
|
||||
|
||||
每一轮结束后,必须能一句话回答下面 3 个问题:
|
||||
|
||||
1. **总计有没有变好?**
|
||||
2. **变好是因为修了脚本、推送系统,还是确认了后端问题?**
|
||||
3. **下一轮只追哪一个主问题?**
|
||||
|
||||
如果一轮总结不能回答这 3 个问题,就说明这轮上下文保留得太多、结论还不够收敛。
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
large_scale_test:
|
||||
config_path: tests/fixtures/auto_sync/auto_test_config.yaml
|
||||
output_dir: test_results/auto_test/large_scale
|
||||
fail_on_failed_cases: false
|
||||
default_runner: aggregate
|
||||
default_init_mode: fresh
|
||||
classification:
|
||||
project::round_3_investment_update: backend
|
||||
material_detail::round_2_update: flaky
|
||||
rounds:
|
||||
- id: round_01_full_baseline
|
||||
title: 全量隔离基线
|
||||
enabled: true
|
||||
runner: aggregate
|
||||
init_mode: fresh
|
||||
objective: 建立当前 19 个 domain 的隔离回归基线,并确认遗留失败的分类。
|
||||
focus:
|
||||
- 全量聚合仍使用每个 domain 独立初始化,避免跨 domain 状态污染。
|
||||
- 先确认 project 与 material_detail 的当前状态,不在本轮混入额外修复动作。
|
||||
next_goal: 在保持全量基线的前提下,单独复核 project 与 material_detail,区分后端遗留问题和聚合偶发问题。
|
||||
- id: round_02_project_recheck
|
||||
title: project 后端复核
|
||||
enabled: true
|
||||
runner: domains
|
||||
init_mode: fresh
|
||||
domains:
|
||||
- project
|
||||
objective: 单独复核 project,确认 round_2 已修复,round_3 仅剩后端读回字段缺失。
|
||||
focus:
|
||||
- 只跑 project,避免无关上下文。
|
||||
- 明确区分脚本问题与后端问题。
|
||||
classification:
|
||||
project::round_3_investment_update: backend
|
||||
next_goal: 保留脚本侧修复结论,把 project round_3 作为后端待修项持续跟踪。
|
||||
- id: round_03_material_detail_recheck
|
||||
title: material_detail 波动复核
|
||||
enabled: true
|
||||
runner: domains
|
||||
init_mode: fresh
|
||||
domains:
|
||||
- material_detail
|
||||
objective: 单独复核 material_detail,确认聚合中的 round_2 失败是否只是偶发。
|
||||
focus:
|
||||
- 只跑 material_detail。
|
||||
- 如果单跑通过,就把聚合中的失败归为 flaky,不扩大处理范围。
|
||||
classification:
|
||||
material_detail::round_2_update: flaky
|
||||
next_goal: 若后续聚合再次出现同类失败,再升级为可复现问题处理。
|
||||
---
|
||||
# 大规模测试控制文档
|
||||
|
||||
这个文档同时承担两件事:
|
||||
|
||||
1. **控制大规模测试怎么跑**
|
||||
2. **记录每轮测试的目标、结果和改进过程**
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 控制入口:调整本文档 frontmatter 中的 `rounds`
|
||||
- 执行脚本:[scripts/run_large_scale_auto_test.py](scripts/run_large_scale_auto_test.py)
|
||||
- 默认命令:`python scripts/run_large_scale_auto_test.py`
|
||||
|
||||
## 设计约束
|
||||
|
||||
- 默认使用 `fresh` 初始化,优先保证每轮从干净环境开始。
|
||||
- `aggregate` runner 适合大规模基线回归;它内部会对每个 domain 独立初始化。
|
||||
- `domains` runner 适合小范围复核;它会按 [scripts/run_auto_test.py](scripts/run_auto_test.py) 的语义执行。
|
||||
- 失败不应靠 fallback 掩盖;应在轮次记录里明确分类。
|
||||
|
||||
## Runner 约定
|
||||
|
||||
### `aggregate`
|
||||
|
||||
- 调用 [scripts/run_auto_test_all_domains.py](scripts/run_auto_test_all_domains.py)
|
||||
- 适合建立全量基线
|
||||
- 最能避免跨 domain 污染
|
||||
|
||||
### `domains`
|
||||
|
||||
- 调用 [scripts/run_auto_test.py](scripts/run_auto_test.py)
|
||||
- 适合复核单个或少量 domain
|
||||
- 用于缩小上下文,验证某个问题是否稳定复现
|
||||
|
||||
## Init 策略约定
|
||||
|
||||
### `fresh`
|
||||
|
||||
- 默认策略
|
||||
- 每轮都从新的初始化开始
|
||||
- 优先用于正式大规模测试
|
||||
|
||||
### `reuse`
|
||||
|
||||
- 透传 `--skip-init`
|
||||
- 只适合排查“连续执行是否污染状态”这一类问题
|
||||
- 不建议作为大规模基线默认值
|
||||
|
||||
### `clear-only`
|
||||
|
||||
- 只清空环境,不执行业务轮次
|
||||
- 用于单独校验清理逻辑
|
||||
|
||||
## 执行记录
|
||||
|
||||
下面这部分由脚本自动更新,不手工编辑。
|
||||
|
||||
<!-- LARGE_SCALE_RESULTS:START -->
|
||||
|
||||
## 最近一次执行 20260308-012707
|
||||
|
||||
- 控制文档: docs/auto_test_spec/large_scale_test_control.md
|
||||
- 执行轮次数: 1
|
||||
- 说明: 默认优先使用 fresh 初始化;若使用 aggregate runner,则每个 domain 仍会独立初始化。
|
||||
|
||||
### 轮次总览
|
||||
|
||||
| Round | 标题 | Runner | Init | Cases | Failed | 对比轮次 | 报告 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| round_01_full_baseline | 全量隔离基线 | aggregate | fresh | 42 | 1 | - | test_results/auto_test/reports/20260308-012707/report.md |
|
||||
|
||||
### round_01_full_baseline - 全量隔离基线
|
||||
|
||||
- 目标: 建立当前 19 个 domain 的隔离回归基线,并确认遗留失败的分类。
|
||||
- 运行方式: aggregate
|
||||
- 初始化策略: fresh
|
||||
- 执行命令: /Users/zyl/my_projects/ecm_sync_system/.venv/bin/python /Users/zyl/my_projects/ecm_sync_system/scripts/run_auto_test_all_domains.py --config tests/fixtures/auto_sync/auto_test_config.yaml
|
||||
- 单轮结果: 41 passed / 1 failed / 42 total cases
|
||||
- Domain 结果: 18 passed / 1 failed / 19 total domains
|
||||
- 原始报告: test_results/auto_test/reports/20260308-012707/report.md
|
||||
- 原始汇总: test_results/auto_test/reports/20260308-012707/summary.json
|
||||
- 本轮关注点:
|
||||
- 全量聚合仍使用每个 domain 独立初始化,避免跨 domain 状态污染。
|
||||
- 先确认 project 与 material_detail 的当前状态,不在本轮混入额外修复动作。
|
||||
- 对比轮次: 无可比较轮次
|
||||
- 可比较 case 数: 0
|
||||
- 对比结果: 本轮没有可比改进项,或与此前轮次无重叠 case。
|
||||
- 失败归因:
|
||||
- project::round_3_investment_update | backend | issues=1 | remote.project 字段校验失败: local=de4dc6d2-ea32-5c04-8430-83145d5d0765 target=f3e02e84-e81c-4aa6-88d4-f5aa108c8227; implementation_estimate: actual=None expected=1225000.0; static_total_investment: actual=None expected=1224300.0; completed_investment: actual=None expected=194500.0
|
||||
- 下一轮目标: 在保持全量基线的前提下,单独复核 project 与 material_detail,区分后端遗留问题和聚合偶发问题。
|
||||
- 脚本返回码: 1
|
||||
|
||||
<!-- LARGE_SCALE_RESULTS:END -->
|
||||
@@ -0,0 +1,42 @@
|
||||
# 差异字段汇总清单
|
||||
|
||||
本文档记录了在同步推流测试中,本地(Local payload)与远端(Remote API 响应/DB落库)产生明确差异的字段。这些差异通常是因为远端后端代码主动忽略了前端传值,并采用关联覆盖、自动计算或默认补全所致。
|
||||
|
||||
> **备注**:
|
||||
> 1. 根据梳理,完全被远端忽略的、只作为返回展示的字段已经从本地/远端的 `Create`、`Update` Schema 中彻底**剔除 (已删)**,不再作为入参推送。
|
||||
> 2. 标有 **[🔥远端接收并参与逻辑计算,但最终与本地不一致]** 的字段没有被删,作为强逻辑关联字段保留。
|
||||
|
||||
## 1. contract_settlement (合同结算)
|
||||
|
||||
### Create 请求 (`ContractSettlementCreate`)
|
||||
- **`contract_type` (合同类型)**: **(从 Schema 彻底剔除)** 远端完全不接收本地传值,根据关联逻辑自动赋予了实际类别(如 `'PC'`, `'GJ'`, `'E'`)。
|
||||
- **`contract_price` (合同总额)**: Create不需要传(本地本身无该入参)。远端在创建时直接从近端 Contract 数据库查取并覆盖。
|
||||
|
||||
### Update / Plan Update 请求 (`ContractSettlementUpdate` 等)
|
||||
- **`plan_complete_date`**: **[🔥远端接收并参与逻辑计算,但最终与本地不一致]** 远端接收该字段,主要作用于 `clean_plan_nodes` 数据清洗以保证非法边界节点被剔除,同时可能经过远端状态与明细上托更新,使得终值可能扭转。
|
||||
- **`complete_price` / `status` / `delay_days` / `statistic_date` / `actual_start_date`**: 远端自动计算累加的衍生只读字段,均不在 Create / Update Schema 范畴中,故不维护入参。
|
||||
|
||||
## 2. construction_task & construction_task_detail (施工任务及明细)
|
||||
|
||||
### Create 请求 (`ConstructionTaskCreate`)
|
||||
- **`contract_quantity` (合同工程量)**: **(已从 Create Schema 彻底剔除)** 远端由于 `create_construction` 函数底层逻辑完全不读此字段,现已被安全双端剪除。不在初始创建时推送。
|
||||
- **`plan_start_date` / `plan_complete_date`**: **[🔥远端接收并参与逻辑计算,但最终与本地不一致]** 远端校验WBS结构树约束时会接收这俩参数进行合规计算,如果超出父子节点范围,存在自动修正或打回改写的逻辑。
|
||||
|
||||
### Update / Plan Update 请求 (`ConstructionTaskUpdate` 及明细)
|
||||
- **`contract_quantity` (合同工程量)**: **[🔥远端接收并参与逻辑计算,但最终与本地不一致]** 在针对 `ConstructionPlanUpdate` 更新计划节点时,远程接受本字段控制计算与校验完成率基准,但仍可能会受 WBS 重制。
|
||||
- **`complete_quantity` / `complete_rate` / `rate` / `status` / `actual_complete_date`**: 纯内部状态更新触发、只读汇总,本地本来就未放至 Update Schema 内进行提交。
|
||||
|
||||
## 3. supplier (供应商)
|
||||
|
||||
### 字段表现
|
||||
- **`city_name`, `province_name`, `country_name`**: Response专用字段。本地不推,仅仅是远端依托外部库映射在接口返回中补全的只读显示。
|
||||
|
||||
## 4. company (组织/公司)
|
||||
|
||||
### 字段表现
|
||||
- **`parent_name` (父级机构名称)**: Response专用显示字段。远端依赖 `parent_id` 自动向上追溯返回字段。
|
||||
|
||||
## 5. production (产值等)
|
||||
|
||||
### Create / Update 请求
|
||||
- **`is_exist`**: **[🔥远端接收并参与逻辑计算,但最终与本地不一致]** 本地推流中有 `is_exist = True`,且远端后端提取了 `production_data.is_exist` 进行存入判断(确实参与了代码落库前置过滤逻辑),但最后远程抓回验证时为 `None`,这归因于远端的废弃映射和覆盖逻辑。该字段须保留不能删。
|
||||
@@ -0,0 +1,165 @@
|
||||
# Collection 查询现状与升级方案
|
||||
|
||||
## 1. 当前实现梳理
|
||||
|
||||
核心代码:
|
||||
- `sync_state_machine/common/collection.py`
|
||||
- `sync_state_machine/common/binding.py`
|
||||
- `sync_state_machine/datasource/datasource.py`
|
||||
- `sync_state_machine/sync_system/strategy_ops/*.py`
|
||||
|
||||
### 1.1 DataCollection 当前内存结构
|
||||
|
||||
`DataCollection` 目前核心是两张索引:
|
||||
- `_nodes: Dict[node_id, SyncNode]`
|
||||
- `_data_id_to_node_id: Dict[data_id, node_id]`
|
||||
|
||||
特点:
|
||||
- `node_id` 查找是 O(1)
|
||||
- `data_id` 反查 node 是 O(1)
|
||||
- 其他查询(按状态/动作/绑定状态/业务字段)目前主要依赖遍历
|
||||
|
||||
### 1.2 查询路径
|
||||
|
||||
#### A. 通用筛选 `filter(...)`
|
||||
- 先取 `_nodes.values()`
|
||||
- 可按 `node_type` 过滤
|
||||
- 可按 `node_filter`(节点顶层属性)过滤
|
||||
- 可按 `filter`(`node.data` 内字段)过滤
|
||||
|
||||
复杂度:最差接近 O(N)
|
||||
|
||||
#### B. 状态筛选 `filter_by_state_ids(...)`
|
||||
- 先调用 `filter(node_type=...)`
|
||||
- 对每个候选节点,根据状态机配置逐条匹配 `binding_status/action/status/data_id_exist`
|
||||
- `state_ids` 多个时,执行多次匹配
|
||||
|
||||
复杂度:约 O(N * |state_ids|)
|
||||
|
||||
### 1.3 调用热点
|
||||
|
||||
在 pipeline 中,以下路径高频调用状态筛选:
|
||||
- bind 阶段(S00)
|
||||
- create 阶段(S06)
|
||||
- update 阶段(S07)
|
||||
- delete 检查(S09)
|
||||
|
||||
对应代码:
|
||||
- `sync_state_machine/datasource/datasource.py` 的 `_sync_nodes`
|
||||
- `sync_state_machine/sync_system/strategy_ops/bind_ops.py`
|
||||
|
||||
### 1.4 BindingManager 当前查询
|
||||
|
||||
`BindingManager` 当前结构:
|
||||
- `_bindings: Dict[node_type, Dict[local_id, remote_id]]`
|
||||
|
||||
其中:
|
||||
- `get_remote_id`:O(1)
|
||||
- `get_local_id`:当前是遍历同类型全部绑定,O(K)
|
||||
|
||||
当绑定数量很大时,`get_local_id` 会成为热点。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本次已修正项
|
||||
|
||||
### 2.1 `filter(data_filter)` 查询中的不必要深拷贝
|
||||
|
||||
原实现在 `filter` 的 data 过滤里每个节点调用 `node.get_data()`,会触发深拷贝,数据量大时会产生明显 CPU/内存开销。
|
||||
|
||||
已改为只读访问 `node.data`:
|
||||
- 不改变返回语义
|
||||
- 降低过滤时的对象复制成本
|
||||
|
||||
变更文件:
|
||||
- `sync_state_machine/common/collection.py`
|
||||
|
||||
### 2.2 类型标注修正
|
||||
|
||||
`node_filter` 的注解从 `callable` 修正为 `Callable[[SyncNode], bool]`,增强类型可读性和 IDE 体验。
|
||||
|
||||
---
|
||||
|
||||
## 3. 升级方案(针对三类目标)
|
||||
|
||||
目标:
|
||||
1) 查询性能
|
||||
2) 架构明确
|
||||
3) 内存数据不过多
|
||||
|
||||
### 阶段 0(当前)
|
||||
- 保持现有语义,先完成可观测性:记录各查询调用次数和耗时(尤其 `filter_by_state_ids` 与 `get_local_id`)
|
||||
|
||||
### 阶段 1(低风险,优先)
|
||||
|
||||
#### 1. 查询性能
|
||||
- 新增二级内存索引(不替换现有结构,仅并行维护):
|
||||
- `by_node_type: Dict[str, Set[node_id]]`
|
||||
- `by_status: Dict[SyncStatus, Set[node_id]]`
|
||||
- `by_action: Dict[SyncAction, Set[node_id]]`
|
||||
- `by_binding_status: Dict[BindingStatus, Set[node_id]]`
|
||||
- `by_type_status_action: Dict[(node_type,status,action), Set[node_id]]`
|
||||
- `filter_by_state_ids` 先用组合索引缩小候选,再做状态机细匹配
|
||||
|
||||
#### 2. 架构明确
|
||||
- 增加查询层接口(例如 `CollectionQueryEngine`),将“筛选逻辑”与“存储结构”分离
|
||||
- 业务侧只依赖查询接口,不直接依赖 `_nodes`
|
||||
|
||||
#### 3. 内存控制
|
||||
- 新增按需字段索引,仅为高频字段建立(如 `project_id/company_id/contract_id`)
|
||||
- 索引集采用 `set[node_id]`,避免复制节点对象
|
||||
|
||||
### 阶段 2(中风险)
|
||||
|
||||
#### 1. 查询性能
|
||||
- `BindingManager` 增加反向索引:
|
||||
- `remote_to_local: Dict[node_type, Dict[remote_id, local_id]]`
|
||||
- 将 `get_local_id` 从 O(K) 降至 O(1)
|
||||
|
||||
#### 2. 架构明确
|
||||
- 统一节点写路径(add/update/delete)触发索引增量更新
|
||||
- 明确“不允许绕过 Collection 写入节点”
|
||||
|
||||
#### 3. 内存控制
|
||||
- 增加可配置的“弱索引模式”:在低内存场景关闭部分次级索引
|
||||
|
||||
### 阶段 3(可选,较高风险)
|
||||
|
||||
#### 1. 查询性能
|
||||
- 引入 SQLite 热查询表(内存 SQLite 或磁盘 SQLite)承接复杂组合查询
|
||||
- 保留内存索引作为热点路径,DB 作为补充查询后端
|
||||
|
||||
#### 2. 架构明确
|
||||
- 形成分层:
|
||||
- 热路径:内存索引
|
||||
- 冷路径:SQLite 查询
|
||||
- 归档:持久化 DB
|
||||
|
||||
#### 3. 内存控制
|
||||
- 支持“分批加载 + 分批同步 + checkpoint”
|
||||
- 将非活跃节点转冷存储,只在命中时回载
|
||||
|
||||
---
|
||||
|
||||
## 4. 启动/重置语义说明(避免误判)
|
||||
|
||||
当前默认不是每次全清空:
|
||||
- 启动会先加载持久化,再执行 E01 归并清理
|
||||
- 仅在 `persist.wipe_on_start=true` 时会在启动前删除持久化 DB
|
||||
|
||||
因此若做“分批/多轮 pipeline”,建议:
|
||||
- 保持 `wipe_on_start=false`
|
||||
- 通过显式 checkpoint 与增量范围控制保证状态一致性
|
||||
|
||||
---
|
||||
|
||||
## 5. 结论
|
||||
|
||||
短期最优路径:
|
||||
- 先完成阶段 1 + 阶段 2(低/中风险),通常能解决大部分查询性能问题
|
||||
- 再根据压测结果决定是否进入阶段 3(SQL 化冷查询)
|
||||
|
||||
这条路线兼顾:
|
||||
- 速度(热路径仍在内存)
|
||||
- 清晰性(查询层解耦)
|
||||
- 内存边界(按需索引 + 分批加载)
|
||||
@@ -0,0 +1,243 @@
|
||||
# 数据源指南(DataSource Guide)
|
||||
|
||||
本文档记录当前项目中不同数据源的职责、能力与配置方式,并按数据源分类说明。
|
||||
|
||||
## 1. 总览
|
||||
|
||||
当前实现包含两类数据源:
|
||||
|
||||
- JSONL 数据源:面向本地文件读写
|
||||
- API 数据源:面向远端 HTTP 接口推送与轮询
|
||||
|
||||
两者都基于统一编排层 `BaseDataSource`,具备一致的流程骨架:
|
||||
|
||||
1. 注册 Handler(按节点类型)
|
||||
2. load 阶段加载节点
|
||||
3. sync 阶段按动作执行 create/update/delete
|
||||
4. 统一处理 TaskResult 与状态机写回
|
||||
5. 统一异步任务轮询(IN_PROGRESS -> SUCCESS/FAILED)
|
||||
|
||||
这意味着:
|
||||
|
||||
- 业务策略可复用,不需关心底层介质差异
|
||||
- 数据源差异主要落在 Handler 与传输/存储细节
|
||||
|
||||
---
|
||||
|
||||
## 2. JSONL 数据源
|
||||
|
||||
### 2.1 主要功能
|
||||
|
||||
JSONL 数据源对应实现:
|
||||
|
||||
- `sync_state_machine/datasource/jsonl/datasource.py`
|
||||
- `sync_state_machine/datasource/jsonl/handler.py`
|
||||
|
||||
核心能力:
|
||||
|
||||
- 从目录中按 `{node_type}_N.jsonl` 规则发现并加载数据
|
||||
- 批量 create/update/delete 时,先改内存缓存,再统一刷盘
|
||||
- 支持 `read_only`,在只读模式下禁止写回
|
||||
- 支持按项目过滤(`target_project_ids`)在 load 阶段预过滤
|
||||
|
||||
### 2.2 行为特点
|
||||
|
||||
- load:逐行解析 JSONL,单行坏数据仅警告并继续
|
||||
- create/update/delete:返回统一 `TaskResult`,由 DataSource 层统一更新状态
|
||||
- 写回:默认写到 `{node_type}_1.jsonl`
|
||||
|
||||
### 2.3 关键配置
|
||||
|
||||
`JsonlDataSourceConfig` 字段:
|
||||
|
||||
- `type: jsonl`
|
||||
- `jsonl_dir`: 数据目录
|
||||
- `read_only`: 是否只读
|
||||
- `target_project_ids`: 项目过滤列表
|
||||
- `handler_configs`: 按节点类型的 handler 参数
|
||||
|
||||
---
|
||||
|
||||
## 3. API 数据源
|
||||
|
||||
### 3.1 主要功能
|
||||
|
||||
API 数据源对应实现:
|
||||
|
||||
- `sync_state_machine/datasource/api/datasource.py`
|
||||
- `sync_state_machine/datasource/api/client.py`
|
||||
- `sync_state_machine/datasource/api/handler.py`
|
||||
|
||||
核心能力:
|
||||
|
||||
- 统一 HTTP 请求入口(签名、uid 注入、错误日志、trace)
|
||||
- 统一 push 任务轮询(`/push/result`)
|
||||
- 统一请求链路追踪(submit/poll/load)
|
||||
- 统一限流(全局窗口限流)
|
||||
|
||||
### 3.2 API 全局限流(重点)
|
||||
|
||||
当前已支持全局异步限流,入口在 `ApiClient.request()` 前。
|
||||
|
||||
配置字段:
|
||||
|
||||
- `api_rate_limit_max_requests`:窗口内最大请求数
|
||||
- `api_rate_limit_window_seconds`:窗口秒数
|
||||
|
||||
默认值:
|
||||
|
||||
- `api_rate_limit_max_requests: 10`
|
||||
- `api_rate_limit_window_seconds: 10.0`
|
||||
|
||||
含义:
|
||||
|
||||
- 任意 10 秒窗口内最多发 10 个请求
|
||||
- 超出后,后续请求在客户端侧等待,不直接打到服务端
|
||||
|
||||
实现机制(简述):
|
||||
|
||||
- 全局 `asyncio.Lock` + 时间戳队列
|
||||
- 发送前清理窗口外时间戳
|
||||
- 若窗口未满,立即占位并发送
|
||||
- 若窗口已满,按最早时间戳计算等待时间后重试
|
||||
|
||||
禁用方式:
|
||||
|
||||
- `api_rate_limit_max_requests <= 0` 或 `api_rate_limit_window_seconds <= 0`
|
||||
|
||||
### 3.3 从 collection 按需提取数据(重点)
|
||||
|
||||
在 API 模式下,Handler 不是盲目请求,而是从 `collection` 按依赖提取后再调用 API。
|
||||
|
||||
常见模式:
|
||||
|
||||
1. load 前置依赖提取
|
||||
- 例如合同 Handler 先从 collection 取 project 节点,再按 project_id 拉合同列表
|
||||
2. create/update 提取上下文
|
||||
- 从 `node.context` 或 `node.get_data()` 中提取依赖字段(如 `project_id`)
|
||||
3. 节点复用/更新
|
||||
- `_create_basic_node` 会优先按 `data_id` 命中已有节点,避免重复节点
|
||||
|
||||
好处:
|
||||
|
||||
- 减少无效 API 调用(按依赖、按项目有选择地加载)
|
||||
- 保持节点关系与上下文完整(project/contract 等依赖链)
|
||||
|
||||
### 3.4 API 校验链路(重点)
|
||||
|
||||
API 数据源中,校验分为三层:
|
||||
|
||||
1. 领域 schema 校验(请求前/响应后)
|
||||
- 例如 `ContractCreate.model_validate(...)`、`ContractUpdate.model_validate(...)`
|
||||
- load 响应也会在解析后转为领域 schema
|
||||
2. 通用更新过滤与差异识别
|
||||
- `_filter_update_data`:仅在 schema 相关字段有变化时提交更新
|
||||
- `_get_schema_diff`:用于差异字段识别与调试输出
|
||||
3. 轮询接口输入校验
|
||||
- `PushIdsSchema` 校验 push_ids 格式后再请求 `/push/result`
|
||||
|
||||
设计原则:
|
||||
|
||||
- 校验失败直接显式失败,不静默降级
|
||||
- 保持状态机与错误日志可追踪
|
||||
|
||||
### 3.5 轮询与结果回写
|
||||
|
||||
- create 可返回 IN_PROGRESS(异步)或 SUCCESS(同步)
|
||||
- `BaseDataSource` 统一轮询并写回节点状态
|
||||
- 结果通过状态机事件落到 SUCCESS/FAILED
|
||||
- create 成功后会进行 `data_id` 回写与 collection 更新(必要时)
|
||||
|
||||
---
|
||||
|
||||
## 4. 配置说明(按数据源区分)
|
||||
|
||||
### 4.1 JSONL 数据源配置示例
|
||||
|
||||
```yaml
|
||||
local_datasource:
|
||||
type: jsonl
|
||||
jsonl_dir: ${PROJECT_ROOT}/filtered_datasource/datasource/filtered
|
||||
read_only: false
|
||||
target_project_ids: []
|
||||
handler_configs: {}
|
||||
```
|
||||
|
||||
### 4.2 API 数据源配置示例(含限流)
|
||||
|
||||
```yaml
|
||||
remote_datasource:
|
||||
type: api
|
||||
api_base_url: http://localhost:8000/api/third/v2
|
||||
api_uid: your_uid
|
||||
api_secret: your_secret
|
||||
api_debug: true
|
||||
|
||||
# 轮询配置
|
||||
poll_max_retries: 1
|
||||
poll_interval: 2.0
|
||||
|
||||
# 全局限流:10 秒最多 10 次请求
|
||||
api_rate_limit_max_requests: 10
|
||||
api_rate_limit_window_seconds: 10.0
|
||||
|
||||
target_project_ids:
|
||||
- "project-id-1"
|
||||
handler_configs: {}
|
||||
```
|
||||
|
||||
### 4.3 配置模型位置
|
||||
|
||||
- `sync_state_machine/config/datasource_config.py`
|
||||
- `JsonlDataSourceConfig`
|
||||
- `ApiDataSourceConfig`
|
||||
|
||||
配置是严格模式(`extra="forbid"`):
|
||||
|
||||
- 未声明字段会报错
|
||||
- 避免运行时拼写错误导致“配置看起来生效、实际未生效”
|
||||
|
||||
---
|
||||
|
||||
## 5. 运行建议与排障
|
||||
|
||||
### 5.1 API 触发限流(429)时
|
||||
|
||||
优先调整:
|
||||
|
||||
- 降低 `api_rate_limit_max_requests`
|
||||
- 提高 `api_rate_limit_window_seconds`
|
||||
|
||||
例如:
|
||||
|
||||
- `api_rate_limit_max_requests: 8`
|
||||
- `api_rate_limit_window_seconds: 10.0`
|
||||
|
||||
### 5.2 轮询超时
|
||||
|
||||
可调整:
|
||||
|
||||
- `poll_max_retries`
|
||||
- `poll_interval`
|
||||
|
||||
总等待时长约为:
|
||||
|
||||
- `poll_max_retries * poll_interval`
|
||||
|
||||
### 5.3 校验失败
|
||||
|
||||
建议直接修数据或 schema,不建议绕过校验;当前链路会保留失败信息用于定位。
|
||||
|
||||
---
|
||||
|
||||
## 6. 相关文件索引
|
||||
|
||||
- `sync_state_machine/datasource/datasource.py`
|
||||
- `sync_state_machine/datasource/jsonl/datasource.py`
|
||||
- `sync_state_machine/datasource/jsonl/handler.py`
|
||||
- `sync_state_machine/datasource/api/datasource.py`
|
||||
- `sync_state_machine/datasource/api/client.py`
|
||||
- `sync_state_machine/datasource/api/handler.py`
|
||||
- `sync_state_machine/config/datasource_config.py`
|
||||
- `run_profiles/jsonl_to_api.yaml`
|
||||
- `run_profiles/preset/jsonl_to_api.default.yaml`
|
||||
@@ -0,0 +1,360 @@
|
||||
# sync_state_machine 接入手册
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本项目现在可以作为可编辑安装库使用:
|
||||
|
||||
- 源码开发:`pip install -e .`
|
||||
- 代码引用:`import sync_state_machine`
|
||||
- 命令行运行:`ecm-sync-run --config_path=...`
|
||||
|
||||
推荐接入方式:
|
||||
|
||||
- `sync_state_machine` 负责同步引擎、状态机、pipeline、datasource 抽象。
|
||||
- 业务系统负责提供自己的数据源适配层,不要反向让 `sync_state_machine` 依赖业务系统。
|
||||
|
||||
---
|
||||
|
||||
## 2. 安装方式
|
||||
|
||||
### 2.1 本仓库本地安装
|
||||
|
||||
在仓库根目录执行:
|
||||
|
||||
```bash
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
安装后可直接使用:
|
||||
|
||||
```python
|
||||
import sync_state_machine
|
||||
print(sync_state_machine.__version__)
|
||||
```
|
||||
|
||||
也可以直接走命令:
|
||||
|
||||
```bash
|
||||
ecm-sync-run --config_path=run_profiles/preset/jsonl_to_api.default.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 对外可直接引用的入口
|
||||
|
||||
常用入口:
|
||||
|
||||
- `sync_state_machine.build_config`
|
||||
- `sync_state_machine.build_default_config`
|
||||
- `sync_state_machine.run_pipeline_from_config`
|
||||
- `sync_state_machine.create_pipeline_from_config`
|
||||
- `sync_state_machine.PipelineRunConfig`
|
||||
- `sync_state_machine.JsonlDataSourceConfig`
|
||||
- `sync_state_machine.ApiDataSourceConfig`
|
||||
- `sync_state_machine.DomainRegistry`
|
||||
|
||||
内置 domain 注册会在导入包时自动完成。
|
||||
|
||||
---
|
||||
|
||||
## 4. 最小接入示例
|
||||
|
||||
### 4.1 直接运行现有 pipeline
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from sync_state_machine import build_config, load_overrides_from_file, run_pipeline_from_config
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
project_root = Path("/path/to/ecm_sync_system")
|
||||
profile_path = project_root / "run_profiles" / "preset" / "jsonl_to_api.default.yaml"
|
||||
|
||||
overrides = load_overrides_from_file(profile_path, project_root)
|
||||
config = build_config(project_root=project_root, overrides=overrides)
|
||||
await run_pipeline_from_config(config, title="demo", print_summary=True)
|
||||
```
|
||||
|
||||
适合场景:
|
||||
|
||||
- 仍沿用当前仓库的 domain 注册
|
||||
- 仍沿用当前仓库的 JSONL / API handler
|
||||
- 外部系统只想“调用引擎”
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据源怎么引用
|
||||
|
||||
当前引擎的 datasource 分两层:
|
||||
|
||||
1. `DataSource`
|
||||
- 管理加载、批量执行、轮询、collection 注入、handler 注册。
|
||||
2. `Handler`
|
||||
- 只处理某一个 `node_type` 的 I/O 逻辑。
|
||||
|
||||
因此接入时,不是“直接把业务 ORM 塞进 pipeline”,而是:
|
||||
|
||||
- 先确定你的数据源类型
|
||||
- 再决定复用已有 datasource,还是只新增 handler
|
||||
|
||||
### 5.1 已有两类 datasource
|
||||
|
||||
#### JSONL
|
||||
|
||||
可直接复用:
|
||||
|
||||
- `sync_state_machine.datasource.JsonlDataSource`
|
||||
- `sync_state_machine.datasource.BaseJsonlHandler`
|
||||
|
||||
适合:
|
||||
|
||||
- 本地 fixture
|
||||
- 离线回放
|
||||
- 调试数据集
|
||||
|
||||
#### API
|
||||
|
||||
可直接复用:
|
||||
|
||||
- `sync_state_machine.datasource.ApiDataSource`
|
||||
- `sync_state_machine.datasource.ApiClient`
|
||||
- `sync_state_machine.datasource.BaseApiHandler`
|
||||
|
||||
适合:
|
||||
|
||||
- HTTP 接口推送
|
||||
- 异步 push + poll
|
||||
- 远端系统同步
|
||||
|
||||
---
|
||||
|
||||
## 6. 怎么适配数据源
|
||||
|
||||
### 6.1 最推荐:复用已有 datasource,只写 handler
|
||||
|
||||
这是最小成本方案。
|
||||
|
||||
比如你的本地数据来自 backend 的数据库,但你不想改引擎核心,可以:
|
||||
|
||||
- 保持 `ApiDataSource` / `JsonlDataSource` 不变
|
||||
- 新增你自己的 handler
|
||||
- 在 handler 里把 backend 数据模型转换成节点 schema
|
||||
|
||||
如果是 HTTP 源:继承 `BaseApiHandler`。
|
||||
|
||||
如果是 JSONL 源:继承 `BaseJsonlHandler`。
|
||||
|
||||
#### API handler 示例
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
from sync_state_machine.datasource.api.handler import BaseApiHandler
|
||||
|
||||
|
||||
class DemoSchema(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
|
||||
|
||||
class DemoApiHandler(BaseApiHandler[DemoSchema]):
|
||||
_node_type = "demo"
|
||||
_node_class = DemoSyncNode
|
||||
_schema = DemoSchema
|
||||
|
||||
async def load(self):
|
||||
payload = await self.api_client.get("/demo/list")
|
||||
return [self._create_node(item) for item in payload["data"]]
|
||||
|
||||
async def create_all(self, nodes):
|
||||
...
|
||||
|
||||
async def update_all(self, nodes):
|
||||
...
|
||||
|
||||
async def delete_all(self, nodes):
|
||||
...
|
||||
|
||||
async def poll_tasks(self, task_ids):
|
||||
...
|
||||
```
|
||||
|
||||
#### JSONL handler 示例
|
||||
|
||||
```python
|
||||
from sync_state_machine.datasource.jsonl.handler import BaseJsonlHandler
|
||||
|
||||
|
||||
class DemoJsonlHandler(BaseJsonlHandler):
|
||||
def __init__(self, datasource):
|
||||
super().__init__(
|
||||
datasource=datasource,
|
||||
node_type="demo",
|
||||
node_class=DemoSyncNode,
|
||||
schema=DemoSchema,
|
||||
)
|
||||
```
|
||||
|
||||
然后把它注册到 `DomainRegistry`。
|
||||
|
||||
---
|
||||
|
||||
### 6.2 如果 backend 是数据库:建议写“数据库 handler / adapter”,不要让引擎直接依赖 ORM
|
||||
|
||||
推荐结构:
|
||||
|
||||
```text
|
||||
backend/
|
||||
app/
|
||||
integrations/
|
||||
ecm_sync/
|
||||
datasource/
|
||||
user_db_handler.py
|
||||
contract_db_handler.py
|
||||
mapper/
|
||||
user_mapper.py
|
||||
contract_mapper.py
|
||||
services/
|
||||
sync_runner.py
|
||||
```
|
||||
|
||||
职责建议:
|
||||
|
||||
- `mapper/`
|
||||
- backend model -> sync schema
|
||||
- sync schema -> backend push payload
|
||||
- `datasource/handler`
|
||||
- 调 repository / service 获取数据
|
||||
- 转成 `SyncNode`
|
||||
- `services/sync_runner.py`
|
||||
- 组装配置并调用 pipeline
|
||||
|
||||
不要这样做:
|
||||
|
||||
- 不要在 `sync_state_machine` 包里 import backend 的 model/repository
|
||||
- 不要让 `DomainRegistry` 注册逻辑散落在 backend 业务层之外
|
||||
|
||||
---
|
||||
|
||||
### 6.3 什么时候需要新增 DataSource 类
|
||||
|
||||
只有当你的 I/O 模型与当前两种 datasource 都不匹配时,才新增 `BaseDataSource` 子类。
|
||||
|
||||
例如:
|
||||
|
||||
- MQ / Kafka 批量消费型源
|
||||
- 直接数据库快照源
|
||||
- 特殊 RPC 源
|
||||
|
||||
此时建议:
|
||||
|
||||
1. 继承 `BaseDataSource`
|
||||
2. 保持接口与现有 datasource 一致:
|
||||
- `register_handler()`
|
||||
- `set_collection()`
|
||||
- `load_all()`
|
||||
- `sync_all()`
|
||||
3. 把“节点类型差异”仍下沉到 handler,不要写死在 datasource 里
|
||||
|
||||
---
|
||||
|
||||
## 7. Domain 怎么注册
|
||||
|
||||
引擎通过 `DomainRegistry` 查找:
|
||||
|
||||
- `schema`
|
||||
- `node_class`
|
||||
- `strategy_class`
|
||||
- `jsonl_handler_class`
|
||||
- `api_handler_class`
|
||||
|
||||
示例:
|
||||
|
||||
```python
|
||||
from sync_state_machine.common.registry import DomainRegistry
|
||||
|
||||
DomainRegistry.register(
|
||||
node_type="demo",
|
||||
schema=DemoSchema,
|
||||
node_class=DemoSyncNode,
|
||||
strategy_class=DemoStrategy,
|
||||
jsonl_handler_class=DemoJsonlHandler,
|
||||
api_handler_class=DemoApiHandler,
|
||||
)
|
||||
```
|
||||
|
||||
如果是 backend 接入,建议在 backend 的 integration 启动阶段集中注册,而不是分散在 controller / service 里。
|
||||
|
||||
---
|
||||
|
||||
## 8. backend 里的推荐接法
|
||||
|
||||
建议 backend 只新增一层 integration:
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from sync_state_machine import build_config, create_pipeline_from_config
|
||||
|
||||
|
||||
async def run_demo_sync() -> None:
|
||||
project_root = Path("/path/to/ecm_sync_system")
|
||||
overrides = {
|
||||
"node_types": ["project", "contract"],
|
||||
"local_datasource": {
|
||||
"type": "jsonl",
|
||||
"jsonl_dir": str(project_root / "tests" / "fixtures" / "demo"),
|
||||
},
|
||||
"remote_datasource": {
|
||||
"type": "api",
|
||||
"api_base_url": "https://example.com",
|
||||
"api_uid": "xxx",
|
||||
"api_secret": "xxx",
|
||||
"target_project_ids": ["demo-project"],
|
||||
},
|
||||
}
|
||||
|
||||
config = build_config(project_root=project_root, overrides=overrides)
|
||||
pipeline = await create_pipeline_from_config(config)
|
||||
await pipeline.run()
|
||||
```
|
||||
|
||||
如果 backend 自己提供本地数据库数据,不要把 backend model 直接灌进 pipeline;先经过 handler / mapper 转成 schema 再进入引擎。
|
||||
|
||||
---
|
||||
|
||||
## 9. 接入时的边界约束
|
||||
|
||||
建议保持下面的依赖方向:
|
||||
|
||||
- `backend integration -> sync_state_machine`
|
||||
- `sync_state_machine -X-> backend`
|
||||
|
||||
这样做的好处:
|
||||
|
||||
- 引擎能独立测试
|
||||
- backend 改 repository 不会直接污染引擎
|
||||
- 后续可以单独发布库
|
||||
|
||||
---
|
||||
|
||||
## 10. 当前阶段建议
|
||||
|
||||
如果项目还在高频迭代,推荐顺序:
|
||||
|
||||
1. 先 `pip install -e .`
|
||||
2. 先在 backend 做 integration 目录,不急着发私有包
|
||||
3. 先接 1~2 个 node_type,跑通完整链路
|
||||
4. 稳定后再考虑拆成正式发布包
|
||||
|
||||
---
|
||||
|
||||
## 11. 相关文件
|
||||
|
||||
- 包入口:[sync_state_machine/__init__.py](../sync_state_machine/__init__.py)
|
||||
- CLI:[sync_state_machine/cli.py](../sync_state_machine/cli.py)
|
||||
- 配置工厂:[sync_state_machine/config](../sync_state_machine/config)
|
||||
- datasource 基础层:[sync_state_machine/datasource](../sync_state_machine/datasource)
|
||||
- pipeline 工厂:[sync_state_machine/pipeline/factory.py](../sync_state_machine/pipeline/factory.py)
|
||||
- domain 注册:[sync_state_machine/common/registry.py](../sync_state_machine/common/registry.py)
|
||||
@@ -0,0 +1,79 @@
|
||||
# 节点状态定义(业务核心)
|
||||
|
||||
本文档定义 `SyncNode` 的状态字段语义,并说明状态机如何把这些语义形式化为可执行规则。
|
||||
|
||||
## 1. 节点状态字段
|
||||
|
||||
### `binding_status`
|
||||
- 含义:绑定判定结果,决定节点是否允许进入 create/update。
|
||||
- 取值:`UNCHECKED | NORMAL | MISSING | PEER_CREATING | WARNING | ABNORMAL | DEPENDENCY_ERROR`
|
||||
|
||||
### `action`
|
||||
- 含义:本轮同步意图。
|
||||
- 取值:`NONE | CREATE | UPDATE | DELETE`
|
||||
- 说明:本项目当前主路径使用 `NONE/CREATE/UPDATE`。
|
||||
|
||||
### `status`
|
||||
- 含义:执行状态。
|
||||
- 取值:`PENDING | IN_PROGRESS | SUCCESS | FAILED | SKIPPED | PRECONDITION_FAILED`
|
||||
|
||||
### `data_id`
|
||||
- 含义:目标系统业务主键是否就绪。
|
||||
- 关键语义:`UPDATE` 路径要求目标节点具备 `data_id`,否则进入 `PRECONDITION_FAILED`。
|
||||
|
||||
### `error`
|
||||
- 含义:阻断/失败原因。
|
||||
- 说明:依赖错误与执行错误都在该字段记录可读原因。
|
||||
|
||||
## 2. 绑定状态业务语义
|
||||
|
||||
| binding_status | 业务语义 | 是否允许进入 create/update |
|
||||
|---|---|---|
|
||||
| `UNCHECKED` | 尚未执行 bind 判定 | 否 |
|
||||
| `NORMAL` | 绑定链路健康,可做差异检测与同步 | 是 |
|
||||
| `MISSING` | 无绑定记录,需做依赖检查与自动绑定/创建策略 | 有条件 |
|
||||
| `PEER_CREATING` | 对侧创建进行中(等待创建提交) | 否(等待 E20 提交) |
|
||||
| `WARNING` | 风险态(如自动绑定歧义/关闭) | 否 |
|
||||
| `ABNORMAL` | 数据损坏或核心绑定异常 | 否 |
|
||||
| `DEPENDENCY_ERROR` | 依赖不可满足 | 否 |
|
||||
|
||||
## 3. create / update 语义
|
||||
|
||||
### create
|
||||
- 来源:`MISSING` 节点在策略允许时生成目标 `CREATE` 节点。
|
||||
- 形式化:`E20/E21` + `spawn_target_node_state: S06`。
|
||||
|
||||
### update
|
||||
- 来源:`NORMAL` 节点差异检测后生成目标 `UPDATE`。
|
||||
- 形式化:`E30`。
|
||||
- 前置失败:目标缺 `data_id` 或依赖 ID 解析失败时进入 `S08`,且必须 `action=UPDATE`。
|
||||
|
||||
## 4. 执行状态语义(datasource)
|
||||
|
||||
- `SUCCESS`:执行成功,必要时回填 `data_id`。
|
||||
- `FAILED`:执行失败,保留错误。
|
||||
- `IN_PROGRESS`:异步任务进行中。
|
||||
- `SKIPPED`:handler 决策跳过;若由 UPDATE 降级为 NONE,则进入 `S14`。
|
||||
- `PRECONDITION_FAILED`:准备阶段失败,不进入实际 API 提交。
|
||||
|
||||
## 5. 状态机形式化映射
|
||||
|
||||
状态机把“业务语义”变成“可执行迁移”:
|
||||
- 语义输入:strategy/datasource 提供 `context`。
|
||||
- 迁移判断:`StateMachineRuntime.dispatch(current_state, event_id, context)`。
|
||||
- 状态落地:`Decision.to_state` 对应 YAML `states[Sxx]`。
|
||||
- 不变量:每次落地后执行 `runtime.check_invariants()`。
|
||||
|
||||
## 6. 关键一致性约束
|
||||
|
||||
- `UNCHECKED` 不允许带动作(`INV-1_UNCHECKED_ACTION_NONE`)。
|
||||
- 阻断态(`ABNORMAL/WARNING/DEPENDENCY_ERROR`)不允许动作(`INV-2_BLOCKING_NO_ACTION`)。
|
||||
- `PRECONDITION_FAILED` 必须 `action=UPDATE`(`INV-3_PRECOND_IMPLIES_UPDATE`)。
|
||||
|
||||
## 7. 当前默认依赖语义(业务取向)
|
||||
|
||||
以下是当前代码默认策略,不是单纯命名差异:
|
||||
- 空依赖引用允许放行(`allow_empty_dependency_ref=True`)。
|
||||
- 依赖节点缺失 `data_id` 默认允许放行(`allow_missing_dep_data_id=True`)。
|
||||
|
||||
这意味着:`DEPENDENCY_ERROR` 的触发更偏向“依赖节点不存在或状态异常”,而不是“依赖节点尚未回填 data_id”。如果要改为严格模式,需要在 strategy 语义层切换该策略并同步文档。
|
||||
@@ -0,0 +1,81 @@
|
||||
# 运维与排障手册(业务视角)
|
||||
|
||||
本文档聚焦两件事:
|
||||
- 出错时先看哪里。
|
||||
- 日志里的状态到底代表什么业务问题。
|
||||
|
||||
## 1. 先看什么(快速定位)
|
||||
|
||||
1. 看运行日志(`sync_log`):
|
||||
- 重点关注 `状态机流转`、`reason=`、`depends=[...]`。
|
||||
2. 看持久化数据库:
|
||||
- 重点字段:`binding_status`、`action`、`status`、`error`。
|
||||
3. 对照状态机文档:
|
||||
- `docs/state_machine.md`
|
||||
- `docs/node_state_definition.md`
|
||||
|
||||
## 2. 阶段化排障
|
||||
|
||||
### 2.1 bind 阶段
|
||||
|
||||
常见表现:节点停在 `S03/S04/S05/S13`。
|
||||
|
||||
- `S03(ABNORMAL)`:节点数据损坏或核心绑定异常。
|
||||
- `S04(WARNING)`:自动绑定关闭、键缺失、歧义等不可自动处理情况。
|
||||
- `S05(DEPENDENCY_ERROR)`:依赖节点不存在或依赖状态不正常。
|
||||
- `S13(PEER_CREATING)`:对侧创建进行中,尚未提交完成。
|
||||
|
||||
典型日志:
|
||||
- `reason=依赖项不满足 | depends=[company_id status=peer_creating -> not_normal]`
|
||||
|
||||
业务解释:
|
||||
- 上游依赖还没进入 `NORMAL`,下游业务会被严格阻断。
|
||||
|
||||
### 2.2 create 阶段
|
||||
|
||||
常见表现:节点长时间停在 `S13` 或 `S10C`。
|
||||
|
||||
- `S13`:已判定需要创建,但创建提交未完成。
|
||||
- `S10C`:CREATE 异步执行中。
|
||||
- `S12C`:CREATE 失败。
|
||||
|
||||
优先检查:
|
||||
- API 侧是否返回任务 ID 与成功回执。
|
||||
- 轮询参数(`poll_max_retries` / `poll_interval`)是否过小。
|
||||
|
||||
### 2.3 update 阶段
|
||||
|
||||
常见表现:节点进入 `S08` 或 `S12U`。
|
||||
|
||||
- `S08(PRECONDITION_FAILED)`:前置条件失败(如缺 data_id、依赖 ID 解析失败)。
|
||||
- `S12U`:UPDATE 调用失败。
|
||||
- `S14`:UPDATE 被 handler 降级为 NONE 并跳过。
|
||||
|
||||
优先检查:
|
||||
- `update_direction` 是否符合预期。
|
||||
- 目标节点是否具备 `data_id`。
|
||||
|
||||
## 3. 常见配置误区与症状
|
||||
|
||||
- `auto_bind=false`
|
||||
- 症状:MISSING 节点更容易进入 `WARNING`,不会走自动创建识别。
|
||||
- `skip_sync=true`
|
||||
- 症状:该类型只加载不执行 bind/create/update,常被误以为“没生效”。
|
||||
- `load_mode=persisted_only`
|
||||
- 症状:数据只来自持久化,不主动拉取新数据。
|
||||
- `update_direction=none`
|
||||
- 症状:不做 update,即使有差异也不会提交更新。
|
||||
|
||||
## 4. 推荐操作顺序
|
||||
|
||||
1. 先用 `run_profiles/preset/jsonl_to_jsonl.default.yaml` 跑通基线。
|
||||
2. 再切到 `run_profiles/*.local.yaml` 做最小覆盖。
|
||||
3. 每次只改一类字段(比如只改 `project` 的依赖策略)。
|
||||
4. 改完看一次 `sync_log`,确认状态流转与预期一致。
|
||||
|
||||
## 5. UI 排障(可选)
|
||||
|
||||
1. 启动:`python -m ui.main --host 127.0.0.1 --port 8765`
|
||||
2. 打开:`http://127.0.0.1:8765`
|
||||
3. 在“运行与日志”查看实时状态变化。
|
||||
4. 在“记录与数据库”检查节点状态与绑定记录。
|
||||
@@ -0,0 +1,143 @@
|
||||
# 运行配置业务说明
|
||||
|
||||
本文档从业务视角说明配置字段含义、对阶段行为的影响,以及推荐的覆盖方式。
|
||||
|
||||
## 1. 推荐使用方式(先 default,再覆盖)
|
||||
|
||||
1. 先使用基线配置运行:
|
||||
- `run_profiles/preset/jsonl_to_jsonl.default.yaml`
|
||||
2. 若需项目定制,再复制为:
|
||||
- `run_profiles/jsonl_to_jsonl.local.yaml`
|
||||
3. 仅改有业务差异的字段,避免一次改太多导致排障困难。
|
||||
|
||||
占位符:
|
||||
- `${PROJECT_ROOT}` 会在运行时替换为项目根目录绝对路径。
|
||||
|
||||
## 2. 顶层字段(你在改什么)
|
||||
|
||||
- `node_types`
|
||||
- 本轮参与同步的业务类型列表。
|
||||
- 顺序会影响依赖链执行时机(当前按 node_type 串行执行 bind/create/update)。
|
||||
- `target_project_ids`
|
||||
- 兼容字段。作为两侧 datasource 的项目白名单兜底值。
|
||||
- 若 datasource 自身配置了 `target_project_ids`,则优先使用 datasource 级配置。
|
||||
- `local_datasource` / `remote_datasource`
|
||||
- 分别定义两侧数据来源与执行端。
|
||||
- `strategies`
|
||||
- 每个业务类型的行为策略(依赖、自动绑定、创建方向、更新方向、跳过等)。
|
||||
- `persist`
|
||||
- 持久化开关与数据库位置。
|
||||
- `logging`
|
||||
- 运行日志输出位置与级别。
|
||||
|
||||
## 3. 数据源字段(DataSource)
|
||||
|
||||
### 3.1 JSONL 数据源
|
||||
|
||||
- `type=jsonl`:使用本地 JSONL 文件作为数据源。
|
||||
- `jsonl_dir`:JSONL 目录路径。
|
||||
- `read_only=false`:允许该侧执行 create/update 回写;若为 true,通常用于只读加载。
|
||||
- `target_project_ids=[]`:该侧项目白名单;为空时不进行项目筛选。
|
||||
- `handler_configs`:预留给各业务 handler 的扩展参数。
|
||||
|
||||
### 3.2 API 数据源
|
||||
|
||||
- `type=api`:对接 HTTP API。
|
||||
- `api_base_url` / `api_uid` / `api_secret`:接口访问参数。
|
||||
- `api_debug`:开启后输出更多调试信息。
|
||||
- `poll_max_retries` / `poll_interval`:异步任务轮询次数与间隔。
|
||||
- `target_project_ids`:**必填**,该侧项目白名单;至少需要指定一个项目ID,以避免加载过多远程数据。
|
||||
- `handler_configs`:业务 handler 扩展参数。
|
||||
|
||||
## 4. 策略字段(Strategy)
|
||||
|
||||
每个 node_type 都建议显式写出以下字段,便于审阅与排障。
|
||||
|
||||
### 4.1 `update_direction`
|
||||
|
||||
- `push`:本地变更推送到远端。
|
||||
- `pull`:远端变更拉取到本地。
|
||||
- `bidirectional`:双向更新(需要明确冲突策略,谨慎使用)。
|
||||
- `none`:关闭 update 阶段。
|
||||
|
||||
### 4.2 `local_orphan_action` / `remote_orphan_action`
|
||||
|
||||
- `create_remote`:本地孤儿创建到远端。
|
||||
- `create_local`:远端孤儿创建到本地。
|
||||
- `none`:不自动创建。
|
||||
- `delete_local` / `delete_remote`:当前主流程未作为默认路径,谨慎使用。
|
||||
|
||||
### 4.3 `auto_bind` / `auto_bind_fields` / `pre_bind_data_id`
|
||||
|
||||
- `auto_bind=true`:在 `S02(MISSING)` 上尝试自动匹配。
|
||||
- `auto_bind=false`:不会做自动匹配,也不会走自动创建识别路径;通常会进入阻断态等待人工处理。
|
||||
- `auto_bind_fields`:自动匹配使用的业务键字段。
|
||||
- `pre_bind_data_id`:显式 data_id 预绑定清单(通用能力),格式为:
|
||||
- `- local_data_id: "..."`
|
||||
` remote_data_id: "..."`
|
||||
- 规则:若两侧数据源都存在这对 data_id 对应节点,且当前无绑定记录,则直接绑定。
|
||||
- 不依赖 `auto_bind/auto_bind_fields`,即使 `auto_bind=false` 也会执行。
|
||||
- 不做业务键一对一匹配检查,按你给定的映射对优先执行。
|
||||
|
||||
### 4.4 `depend_fields`
|
||||
|
||||
- 定义依赖字段到依赖 node_type 的映射,例如:`company_id -> company`。
|
||||
- 依赖节点状态非 `NORMAL` 时,会在 bind 的依赖检查阶段进入 `DEPENDENCY_ERROR`。
|
||||
|
||||
### 4.5 `skip_sync`
|
||||
|
||||
- 运行配置中已不建议使用 `skip_sync`。
|
||||
- 推荐使用显式组合:
|
||||
- `local_orphan_action: none`
|
||||
- `remote_orphan_action: none`
|
||||
- `update_direction: none`
|
||||
- 当三者同时为 `none/none/none` 时,pipeline 会跳过该 node_type 的 bind/create/update。
|
||||
|
||||
### 4.6 Handler 级参数(`handler_configs`)
|
||||
|
||||
- 建议将 handler 特有参数放在 datasource 的 `handler_configs.<node_type>` 下。
|
||||
- 示例:
|
||||
- `remote_datasource.handler_configs.supplier.load_mode: persisted_only`
|
||||
- `persisted_only` 表示只使用已持久化数据,不主动从外部拉新数据(具体以对应 handler 实现为准)。
|
||||
|
||||
## 5. 阶段行为与配置关系
|
||||
|
||||
- bind 阶段
|
||||
- `depend_fields` 决定是否做依赖校验。
|
||||
- `pre_bind_data_id` 先按显式 local/remote data_id 映射做预绑定。
|
||||
- `auto_bind/auto_bind_fields` 决定是否继续进行业务键自动绑定。
|
||||
- create 阶段
|
||||
- `local_orphan_action` / `remote_orphan_action` 决定孤儿是否创建。
|
||||
- update 阶段
|
||||
- `update_direction` 决定是否和向哪侧更新。
|
||||
- 写入后 reload(Pipeline 内置)
|
||||
- 当某个 node_type 的 create 或 update 发生实际写入成功后,pipeline 会自动对该 node_type 重新执行两侧 `load`。
|
||||
- 目的:让后续 update 判断基于最新远端/本地数据,支持“create 后再补一次 update”的链路。
|
||||
- 同步后一致性检查(Pipeline 内置)
|
||||
- 每个 node_type 在本轮同步后会基于绑定对执行数据一致性校验(比较时忽略 `id/_id` 字段)。
|
||||
- 若发现差异,会在日志中打印差异样本,并在汇总表新增 `Consistent` 列展示 `Y` / `N(差异数)`。
|
||||
- 全局跳过
|
||||
- `local_orphan_action=none` + `remote_orphan_action=none` + `update_direction=none`
|
||||
可直接跳过该类型的 bind/create/update。
|
||||
|
||||
## 6. 覆盖配置建议
|
||||
|
||||
- 先在 default 跑通一轮,再做 local 覆盖。
|
||||
- 每次只改一类问题相关字段(例如只改 `project` 的依赖与自动绑定)。
|
||||
- 覆盖后优先看 `sync_log` 是否出现预期状态迁移。
|
||||
|
||||
## 7. 持久化与日志字段
|
||||
|
||||
### `persist`
|
||||
|
||||
- `enable`:是否开启持久化。
|
||||
- `db_path`:SQLite 路径。
|
||||
- `wipe_on_start`:启动是否清理历史持久化。
|
||||
|
||||
### `logging`
|
||||
|
||||
- `file_dir`:日志目录。
|
||||
- `file_name_pattern`:文件命名模板。
|
||||
- `level`:日志级别。
|
||||
|
||||
排障建议:运行失败时优先看日志中的 `状态机流转` 与 `reason=`,再对照 `docs/state_machine.md` 与 `docs/node_state_definition.md` 理解含义。
|
||||
@@ -0,0 +1,93 @@
|
||||
# 状态机形式化说明(与代码一致)
|
||||
|
||||
## 1. 真源与执行入口
|
||||
- 配置真源:`sync_state_machine/config/node_state_machine.yaml`
|
||||
- 事件入口:`sync_state_machine/engine/events.py`
|
||||
- 状态落地:`sync_state_machine/engine/state_apply.py`
|
||||
- 不变量校验:`events._apply_decision()` 内调用 `runtime.check_invariants()`
|
||||
|
||||
## 2. 状态集合(Sxx)
|
||||
- `S00`:bind 起点(`UNCHECKED/NONE/PENDING`)
|
||||
- `S01`:NORMAL,待后续 create/update 判定
|
||||
- `S02`:MISSING,待依赖检查/自动绑定/create
|
||||
- `S03`:ABNORMAL,阻断
|
||||
- `S04`:WARNING,阻断
|
||||
- `S05`:DEPENDENCY_ERROR,阻断
|
||||
- `S06`:CREATE 待执行(目标节点)
|
||||
- `S07`:UPDATE 待执行(`action=UPDATE,status=PENDING`)
|
||||
- `S08`:UPDATE 前置失败(`action=UPDATE,status=PRECONDITION_FAILED`)
|
||||
- `S10C/S10U/S10D`:按动作拆分的执行中状态
|
||||
- `S11C/S11U/S11D`:按动作拆分的执行成功状态
|
||||
- `S12C/S12U/S12D`:按动作拆分的执行失败状态
|
||||
- `S13`:对侧创建等待态(`PEER_CREATING/NONE/PENDING`)
|
||||
- `S14`:UPDATE 运行时降级为 `NONE` 并跳过
|
||||
|
||||
## 3. 事件到代码映射
|
||||
|
||||
### bootstrap
|
||||
- `E01`:`engine/events.py::e01_bootstrap()`
|
||||
|
||||
### bind
|
||||
- `E10`:`engine/events.py::e10_bind_core()`
|
||||
- `E15`:`engine/events.py::e15_bind_dependency()`
|
||||
- `E16`:`engine/events.py::e16_bind_auto()`(自动绑定判定;`ZERO+create_enabled=true` 时进入 `S13`,等待创建副作用提交)
|
||||
|
||||
### create/update prepare
|
||||
- `E20`:`engine/events.py::e20_create_prepare()`(spawn 成功从 `S13` 提交到 `S01`;失败保持 `S13`)
|
||||
- `E21`:`engine/events.py::e21_create_prepare()`
|
||||
- `E30`:`engine/events.py::e30_update_prepare()`
|
||||
|
||||
### sync execute
|
||||
- `E40C_START/E40C`:CREATE 执行入口与结果回写
|
||||
- `E40U_START/E40U`:UPDATE 执行入口与结果回写
|
||||
- `E40D_START/E40D`:DELETE 执行入口与结果回写
|
||||
|
||||
## 4. strategy 调用链(当前)
|
||||
- bind 主入口:`sync_system/strategy.py::DefaultSyncStrategy.bind()` -> `strategy_ops/bind_ops.py::run_bind()`
|
||||
- create 主入口:`sync_system/strategy.py::DefaultSyncStrategy.create()` -> `strategy_ops/create_ops.py::run_create()`
|
||||
- update 主入口:`sync_system/strategy.py::DefaultSyncStrategy.update()` -> `strategy_ops/update_ops.py::run_update()`
|
||||
- reset 主入口:`sync_system/strategy.py::BaseSyncStrategy.run_reset()` -> `strategy_ops/reset_ops.py::run_phase2_cleanup()`
|
||||
|
||||
## 5. context 字段(以 YAML 为准)
|
||||
|
||||
### bind 相关
|
||||
- `has_binding_record`
|
||||
- `core_binding_result` / `peer_core_binding_result` (`NORMAL|WARNING|ABNORMAL`)
|
||||
- `data_present`
|
||||
- `has_depend_fields`
|
||||
- `dep_satisfied`
|
||||
- `auto_bind_enabled`
|
||||
- `auto_bind_outcome` (`ONE_TO_ONE|AMBIGUOUS|ZERO|KEY_MISSING|KEY_ID_RESOLVE_FAIL|DATA_MISSING`)
|
||||
|
||||
### create/update 相关
|
||||
- `create_enabled`
|
||||
- `create_id_resolve_ok`
|
||||
- `spawn_success`
|
||||
- `update_enabled`
|
||||
- `target_has_data_id`
|
||||
- `update_id_resolve_ok`
|
||||
- `has_diff`
|
||||
|
||||
### execute 相关
|
||||
- `handler_result` (`SUCCESS|FAILED|SKIPPED|IN_PROGRESS`)
|
||||
- `poll_timeout`
|
||||
|
||||
## 6. 语义边界
|
||||
- strategy 负责业务语义计算(如依赖是否满足、自动绑定结果、差异检测)。
|
||||
- 状态机只负责迁移判定与不变量校验,不直接访问数据源。
|
||||
|
||||
## 7. 不变量
|
||||
- `INV-1_UNCHECKED_ACTION_NONE`
|
||||
- `INV-2_BLOCKING_NO_ACTION`
|
||||
- `INV-3_PRECOND_IMPLIES_UPDATE`
|
||||
|
||||
当状态落地后违反 invariant,运行时会直接抛错。
|
||||
|
||||
## 8. 校验与出图
|
||||
1. `python tools/validate_config.py --config sync_state_machine/config/node_state_machine.yaml`
|
||||
2. `python tools/render_graph.py --config sync_state_machine/config/node_state_machine.yaml --format mermaid --out docs/state_machine.mmd`
|
||||
|
||||
## 9. 事件意图命名(图示层)
|
||||
- 为了让流程意图更直观,图示可使用 `E01.reset.* / E10.core.* / E20.create.* / E30.update.* / E40<action>.* / E41.create.*` 这类别名。
|
||||
- 别名仅用于图标签;运行时事件 ID 仍以 YAML 中 `E01/E10/E15/E16/E20/E21/E30/E40C_START/E40C/E40U_START/E40U/E40D_START/E40D/E41` 为准。
|
||||
- `S10C/S10U/S10D` 与 `S11C/S11U/S11D` 现已是配置中的真实状态 ID(不再是图示别名)。
|
||||
@@ -0,0 +1,68 @@
|
||||
flowchart LR
|
||||
|
||||
subgraph BOOT["Bootstrap / Reset"]
|
||||
S00["S00<br/>进入 bind 前的唯一起点<br/>binding_status: UNCHECKED<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S15(["S15<br/>节点被清理删除(zombie cleanup)"])
|
||||
S16(["S16<br/>持久化加载输入态:本轮 E01 的输入节点集合(可包含上轮遗留与已稳定节点)"])
|
||||
S17(["S17<br/>加载异常隔离态:持久化枚举非法,保留错误供人工处理,不进入自动流程"])
|
||||
end
|
||||
|
||||
subgraph BIND["Binding"]
|
||||
S01["S01<br/>绑定正常(待后续 update 检查)<br/>binding_status: NORMAL<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S02["S02<br/>孤儿节点(可能进入 create / auto_bind / delete)<br/>binding_status: MISSING<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S03["S03<br/>数据损坏/缺失(阻断态,需人工)<br/>binding_status: ABNORMAL<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S04["S04<br/>不可自动处理(阻断态,需人工)<br/>binding_status: WARNING<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S05["S05<br/>依赖项不满足/ID解析失败(阻断态)<br/>binding_status: DEPENDENCY_ERROR<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S13["S13<br/>对侧创建进行中(本侧等待提交)<br/>binding_status: PEER_CREATING<br/>action: NONE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
end
|
||||
|
||||
subgraph CREATE["Create"]
|
||||
S06(["S06<br/>待执行 CREATE(执行入口)<br/>binding_status: NORMAL<br/>action: CREATE<br/>status: PENDING<br/>data_id_exist: false<br/>"])
|
||||
S10C["S10C<br/>CREATE 异步执行中<br/>binding_status: NORMAL<br/>action: CREATE<br/>status: IN_PROGRESS<br/>data_id_exist: false<br/>"]
|
||||
S11C["S11C<br/>CREATE 执行成功<br/>binding_status: NORMAL<br/>action: CREATE<br/>status: SUCCESS<br/>data_id_exist: true<br/>"]
|
||||
S12C["S12C<br/>CREATE 执行失败<br/>binding_status: NORMAL<br/>action: CREATE<br/>status: FAILED<br/>data_id_exist: false | true<br/>"]
|
||||
end
|
||||
|
||||
subgraph UPDATE["Update"]
|
||||
S07["S07<br/>准备更新<br/>binding_status: NORMAL<br/>action: UPDATE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S08["S08<br/>更新前置失败(缺 data_id / 依赖ID未解析等)<br/>binding_status: NORMAL<br/>action: UPDATE<br/>status: PRECONDITION_FAILED<br/>data_id_exist: false | true<br/>"]
|
||||
S10U["S10U<br/>UPDATE 异步执行中<br/>binding_status: NORMAL<br/>action: UPDATE<br/>status: IN_PROGRESS<br/>data_id_exist: true<br/>"]
|
||||
S11U["S11U<br/>UPDATE 执行成功<br/>binding_status: NORMAL<br/>action: UPDATE<br/>status: SUCCESS<br/>data_id_exist: true<br/>"]
|
||||
S12U["S12U<br/>UPDATE 执行失败<br/>binding_status: NORMAL<br/>action: UPDATE<br/>status: FAILED<br/>data_id_exist: false | true<br/>"]
|
||||
S14["S14<br/>更新被跳过(执行时降级为 NONE)<br/>binding_status: NORMAL<br/>action: NONE<br/>status: SKIPPED<br/>data_id_exist: true<br/>"]
|
||||
end
|
||||
|
||||
subgraph DELETE["Delete"]
|
||||
S09["S09<br/>待执行 DELETE(执行入口)<br/>binding_status: NORMAL<br/>action: DELETE<br/>status: PENDING<br/>data_id_exist: true<br/>"]
|
||||
S10D["S10D<br/>DELETE 异步执行中<br/>binding_status: NORMAL<br/>action: DELETE<br/>status: IN_PROGRESS<br/>data_id_exist: true<br/>"]
|
||||
S11D["S11D<br/>DELETE 执行成功(随后删除节点)<br/>binding_status: NORMAL<br/>action: DELETE<br/>status: SUCCESS<br/>data_id_exist: true<br/>"]
|
||||
S12D["S12D<br/>DELETE 执行失败<br/>binding_status: NORMAL<br/>action: DELETE<br/>status: FAILED<br/>data_id_exist: false | true<br/>"]
|
||||
end
|
||||
|
||||
S00 -- "E10a 核心绑定判定" --> S01
|
||||
S00 -- "E10e 核心绑定判定" --> S02
|
||||
S00 -- "E10c 核心绑定判定, E10d 核心绑定判定" --> S03
|
||||
S00 -- "E10b 核心绑定判定" --> S04
|
||||
S01 -- "E30c 更新准备" --> S07
|
||||
S01 -- "E30a 更新准备, E30b 更新准备" --> S08
|
||||
S02 -- "E16c 自动绑定(1:1)" --> S01
|
||||
S02 -- "E15b 依赖检查" --> S03
|
||||
S02 -- "E15a 依赖检查, E16a 自动绑定, E16b 自动绑定, E16d 自动绑定, E16e 自动绑定, E16h 自动绑定(N:0)" --> S04
|
||||
S02 -- "E15c 依赖检查, E16f 自动绑定, E21a 创建依赖解析失败" --> S05
|
||||
S02 -- "E22a 孤儿自删准备" --> S09
|
||||
S02 -- "E16g 自动绑定(N:0)" --> S13
|
||||
S06 -- "E40C_STARTa CREATE 执行入口" --> S10C
|
||||
S07 -- "E40U_STARTa UPDATE 执行入口" --> S10U
|
||||
S09 -- "E40D_STARTa DELETE 执行入口" --> S10D
|
||||
S10C -- "E40Ca CREATE 执行结果回写" --> S11C
|
||||
S10C -- "E40Cb CREATE 执行结果回写" --> S12C
|
||||
S10D -- "E40Da DELETE 执行结果回写" --> S11D
|
||||
S10D -- "E40Db DELETE 执行结果回写" --> S12D
|
||||
S10U -- "E40Ua UPDATE 执行结果回写" --> S11U
|
||||
S10U -- "E40Ub UPDATE 执行结果回写" --> S12U
|
||||
S10U -- "E40Uc UPDATE 执行结果回写" --> S14
|
||||
S11C -- "E41a 创建成功后归并到 update …" --> S01
|
||||
S13 -- "E20a 创建准备阶段2" --> S01
|
||||
S16 -- "E01b 初始化:删CREATE僵尸;其余…" --> S00
|
||||
S16 -- "E01a 初始化:删CREATE僵尸;其余…" --> S15
|
||||
S13 -. "副作用: E16识别需创建后,对侧spawn S06" .-> S06
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 587 KiB |
@@ -0,0 +1,107 @@
|
||||
# 同步流程(pipeline -> strategy -> datasource)
|
||||
|
||||
## 1. 全流程主线
|
||||
1. pipeline 装配组件并加载持久化。
|
||||
2. pipeline 调用 `strategy.bind()`。
|
||||
3. pipeline 调用 `strategy.create()` / `strategy.update()` 生成动作节点。
|
||||
4. pipeline 调用 `datasource.sync_all()` 执行动作并回写执行状态。
|
||||
5. pipeline 输出统计并持久化。
|
||||
|
||||
## 2. reset 时序
|
||||
|
||||
### 2.1 加载时 reset(phase1 语义)
|
||||
- 在 `common/collection.py::load_from_persistence()` 执行。
|
||||
- 语义:仅恢复持久化状态(不在此阶段做状态归并)。
|
||||
|
||||
### 2.2 加载后 cleanup(phase2 语义)
|
||||
- pipeline 调用 `BaseSyncStrategy.run_reset()`。
|
||||
- 实际实现:`strategy_ops/reset_ops.py::run_phase2_cleanup()`。
|
||||
- 核心事件:`E01`(`S16 -> S00/S15`)。
|
||||
- `S16` 表示“持久化加载输入态”:本轮从持久化恢复出的节点集合(可包含上轮遗留节点,也可包含上轮已稳定节点)。
|
||||
- 判定:
|
||||
- `is_create_zombie=true` -> `S15`,节点删除(并尝试解绑);
|
||||
- `is_create_zombie=false` -> `S00`,节点归并为 `UNCHECKED/NONE/PENDING` 并清空 `error`。
|
||||
|
||||
### 2.2.1 `enable_persistence` 与 bootstrap 关系
|
||||
- `enable_persistence=true`:先 `load_from_persistence()`,再对加载出的节点执行 `E01`(`S16` 域内处理)。
|
||||
- `enable_persistence=false`:本轮没有持久化输入,`S16/E01` 不参与;随后 Stage1 新加载节点直接进入本轮 bind/create/update/sync 主流程。
|
||||
|
||||
### 2.3 加载异常隔离(S17)
|
||||
- 持久化中若出现非法枚举值(`action/status/binding_status`),节点标记为 `bootstrap_blocked`(`S17` 语义)。
|
||||
- 这类节点保留 `error`,用于人工排查。
|
||||
- 这类节点不会进入 `E01`,也不会参与 bind/create/update/sync 自动流程。
|
||||
|
||||
## 3. bind 流程(strategy_ops)
|
||||
- 入口:`strategy_ops/bind_ops.py::run_bind()`
|
||||
- 入口状态:`S00`
|
||||
|
||||
### 核心绑定判定
|
||||
- `phase_core_state()` 内触发 `E10`。
|
||||
- 有绑定记录:根据本端/对端有效性进入 `S01/S03/S04`。
|
||||
- 无绑定记录:进入 `S02`。
|
||||
|
||||
### 依赖检查
|
||||
- `phase_dependency_check()` -> `check_dependencies_for_nodes()` 内触发 `E15`。
|
||||
- `data_present=false` -> `S03`。
|
||||
- `dep_satisfied=false` -> `S05`。
|
||||
- `depend_fields` 为空 -> `S04`(无法自动处理,阻断后续自动创建)。
|
||||
|
||||
### 自动绑定
|
||||
- `phase_auto_binding()` 内触发 `E16`。
|
||||
- `ONE_TO_ONE` -> `S01`;`AMBIGUOUS/KEY_MISSING/DATA_MISSING` -> `S04`;`KEY_ID_RESOLVE_FAIL` -> `S05`。
|
||||
- `ZERO + create_enabled=true` -> `S13`(`PEER_CREATING/NONE/PENDING`,待对侧创建中间态);`ZERO + create_enabled=false` -> `S04`。
|
||||
- `auto_bind=false` 时,`E16` 直接落 `S04`(自动绑定未启用),不会进入自动创建路径。
|
||||
|
||||
## 4. create/update 准备
|
||||
|
||||
### create
|
||||
- 入口:`strategy_ops/create_ops.py::run_create()`
|
||||
- 运行时事件:`E20`(`E21/E22` 为配置保留分支,当前 strategy 未接入自动执行)
|
||||
- 运行时入口状态:`S13`
|
||||
- 说明:`E16` 负责识别“需自动创建”并将源节点置为 `S13`;业务代码执行对侧 spawn+bind 后,再通过 `E20` 将 `S13` 提交到 `S01`(成功);若 spawn 失败,`E20` 不迁移并保留在 `S13` 等待人工/重试。
|
||||
- `data_id` 约束:
|
||||
- `S13/S01` 要求源节点 `data_id` 存在(`data_id_exist=true`)。
|
||||
- 新创建目标节点在 `S06/S10C` 阶段允许 `data_id` 为空;`CREATE SUCCESS`(`S11C`)必须携带非空 `result_data_id`,否则事件直接报错。
|
||||
|
||||
### update
|
||||
- 入口:`strategy_ops/update_ops.py::run_update()`
|
||||
- 事件:`E30`
|
||||
- 入口状态(source 节点):`S01`
|
||||
- `target_has_data_id=false` 或 `update_id_resolve_ok=false` -> `S08`
|
||||
- `has_diff=true` -> `S07`
|
||||
|
||||
### post-create 归并
|
||||
- 入口:`pipeline/full_sync_pipeline.py::normalize_create_success_to_update_entry()`
|
||||
- 事件:`E41`
|
||||
- 语义:`CREATE` 执行成功后,节点先落 `S11C`(SUCCESS),再归并 `S11C -> S01`,作为同轮 update 起点。
|
||||
|
||||
## 5. 执行回写(datasource)
|
||||
- 入口:`datasource/datasource.py`
|
||||
- 事件:`E40C_START/E40C`、`E40U_START/E40U`、`E40D_START/E40D`
|
||||
- 当前约束:delete stage 尚未接入 strategy 主流程;若运行时检测到 `S09/DELETE` 节点,DataSource 会显式抛错阻断(避免散落删除执行)。
|
||||
- 执行准备入口状态:
|
||||
- `CREATE`: `S06`
|
||||
- `UPDATE`: `S07`
|
||||
- `DELETE`: `S09`
|
||||
- `S10` 为执行中状态(由本轮执行产生),执行流转固定为“入口 -> S10 -> 终态”,不再出现入口直接到成功/失败。
|
||||
- 结果:
|
||||
- `SUCCESS -> S11C | S11U | S11D`(按动作)
|
||||
- `FAILED -> S12C | S12U | S12D`(按动作)
|
||||
- `IN_PROGRESS -> S10C | S10U | S10D`(按动作,支持异步 polling 闭环)
|
||||
- `SKIPPED + action=UPDATE -> S14`
|
||||
|
||||
## 6. 各阶段入口状态总表
|
||||
|
||||
| 阶段 | 入口状态 | 说明 |
|
||||
|---|---|---|
|
||||
| Reset(E01) | `S16` | create_zombie -> `S15`;其余 -> `S00` |
|
||||
| Bind(E10/E15/E16) | `S00` | bind 三段统一从 `S00` 进入 |
|
||||
| Create Prepare(E20/E21/E22) | `S02` / `S13` | 配置入口含 `S02/S13`;当前 strategy 运行时只处理 `S13` 的 `E20` 提交,`S02` 分支保留未接入 |
|
||||
| Post-create Ready(E41) | `S11C` | `CREATE` 成功节点归并到 `S01`,进入同轮 update |
|
||||
| Update Prepare(E30) | `S01` | 仅从 NORMAL 继续判定(create 成功先经 E41 归并) |
|
||||
| Sync Execute(E40C/U/D) | `S06` / `S07` / `S09` / `S10C` / `S10U` / `S10D` | 执行与回写:按动作分事件;入口先进入 `S10*`,再由 `S10*` 进入 `S11*`/`S12*`;轮询返回 `IN_PROGRESS` 时只记录任务进度,不新增状态迁移;仅 UPDATE 可走 `S14` |
|
||||
| 隔离(人工) | `S17` | 不参与自动阶段,仅人工处理 |
|
||||
|
||||
## 7. 不变量保障
|
||||
- 每次事件落地后,`engine/events.py::_apply_decision()` 会执行 `runtime.check_invariants()`。
|
||||
- 违反 invariant 直接抛错,终止当前路径。
|
||||
@@ -0,0 +1,158 @@
|
||||
# 同步问题分析(2026-03-05)
|
||||
|
||||
## 背景
|
||||
|
||||
- 同步方式:先用 `working_local_datasource/filtered` 初始化远程数据库,再基于 `run_profiles/jsonl_to_api.yaml` 执行 `jsonl -> api` 同步。
|
||||
- 本文基于日志 `test_results/sync_state_machine/simple_pipeline_sm_20260305_102926.log` 与状态库 `test_results/sync_state_machine/simple_pipeline_sm.db`。
|
||||
|
||||
## 总体结果
|
||||
|
||||
- Pipeline 统计:`loaded=311, synced=204, failed=8, post_check_passed=True, mismatch_types=4`
|
||||
- 不一致类型:`company`, `construction_task`, `material`, `contract_settlement`
|
||||
- 其中失败(`failed=8`)全部集中在 `contract_settlement` 的 `UPDATE` 阶段。
|
||||
|
||||
## 自动绑定问题
|
||||
|
||||
> 注:本轮日志已降噪,自动绑定明细多数为 debug 级;以下结论来自 sqlite 状态库查询。
|
||||
|
||||
### 非 normal 绑定状态
|
||||
|
||||
1. `local.construction_task_detail` 1 条 `dep_err`
|
||||
- 错误:依赖 `parent_id -> construction_task` 未找到
|
||||
- 现象:`depends=[parent_id:construction_task data_id=... -> not_found]`
|
||||
- 结论:这是明确的依赖绑定失败(上游父节点缺失或 data_id 不可达)。
|
||||
|
||||
2. `local.project_detail_data` 2 条 `warning`
|
||||
- 错误:`未匹配到候选节点且不允许创建`
|
||||
- 结论:策略配置不允许创建,且自动匹配未命中,属于预期拦截,不是执行异常。
|
||||
|
||||
除上述 3 条外,主要业务类型绑定状态均为 `normal`。
|
||||
|
||||
## 更新后仍不一致(按类型)
|
||||
|
||||
### 1) company(1/1 不一致)
|
||||
|
||||
- 差异字段:`city_name`, `province_name`, `parent_name`
|
||||
- 模式:本地有值,远端为 `None`
|
||||
- 结论:远端 list 返回字段缺失/置空,导致 post-check 一定失败。
|
||||
|
||||
### 2) construction_task(12/32 不一致)
|
||||
|
||||
- 典型残留字段:
|
||||
- `status`
|
||||
- `complete_quantity`, `complete_rate`
|
||||
- `actual_complete_date`, `statistic_date`, `delay_days`
|
||||
- `plan_node`(特别是 `is_audit` 值)
|
||||
- 模式:远端回读为 `None`/`0.0`/默认值,而本地有业务值。
|
||||
- 结论:该类字段主要受后端计算/回写策略影响,当前 update API 无法完全收敛到本地口径。
|
||||
|
||||
### 3) material(3/20 不一致)
|
||||
|
||||
- 典型残留字段:
|
||||
- `complete_quantity`, `complete_rate`
|
||||
- `actual_start_date`, `status`, `delay_days`
|
||||
- `plan_node.is_audit`
|
||||
- 模式与 construction_task 一致:部分字段被后端默认化或不回写。
|
||||
- 结论:属于“可更新字段集合与回读字段集合不一致”导致的残留差异。
|
||||
|
||||
### 4) contract_settlement(34/34 不一致,最严重)
|
||||
|
||||
- 全量普遍差异:`contract_type`(本地 `None`,远端有值如 `DP/GP/...`)
|
||||
- 伴随差异:`complete_price`, `contract_price`, `actual_start_date`, `plan_complete_date`, `plan_node`, `status` 等
|
||||
- 执行结果(remote):`UPDATE SUCCESS=1, FAILED=8, SKIPPED=25`
|
||||
- 8 条失败统一报错:`API error: 计划节点时间必须 晚于计划开始时间`
|
||||
- 结论:
|
||||
- 一部分差异来自字段语义不一致(如 `contract_type`)
|
||||
- 一部分差异来自计划节点 API 校验失败,导致更新无法落库
|
||||
- 因此该类型短期内无法靠重跑自动收敛
|
||||
|
||||
## 根因归类
|
||||
|
||||
### A. 后端返回口径与本地模型口径不一致
|
||||
|
||||
- 典型:`company` 的名称类字段、`construction/material` 的状态/累计/统计字段。
|
||||
|
||||
### B. 更新 schema/API 覆盖范围有限
|
||||
|
||||
- 某些字段在 response 中存在,但不在 update schema 或后端 update 逻辑中生效。
|
||||
|
||||
### C. 计划节点约束导致更新失败
|
||||
|
||||
- `contract_settlement` 明确出现计划节点时间校验失败,直接阻断更新。
|
||||
|
||||
### D. 依赖链局部断裂
|
||||
|
||||
- `construction_task_detail` 存在 parent 依赖找不到,导致绑定 `dep_err`。
|
||||
|
||||
## 建议优先级(不改代码版)
|
||||
|
||||
1. **先处理 contract_settlement 的计划节点校验失败**
|
||||
- 这是唯一明确执行失败来源(8 条),修复后可显著降低不一致。
|
||||
|
||||
2. **明确“应比对字段白名单”与“只读/回写字段”**
|
||||
- 对 `construction_task/material/company` 区分“业务必须一致字段”与“后端派生/可忽略字段”。
|
||||
|
||||
3. **修复依赖断裂样本**
|
||||
- 针对 `construction_task_detail` 的 `parent_id` 失配,核对父节点是否在过滤阶段被裁掉或 data_id 不一致。
|
||||
|
||||
4. **针对 `project_detail_data` 的 warning 决策**
|
||||
- 确认是否允许创建;若业务上应存在,需调整策略配置。
|
||||
|
||||
---
|
||||
|
||||
如果需要,我可以基于本文再拆成一份“可执行排障清单”(按 SQL/API/配置三条线),每条给出具体核对命令与验收标准。
|
||||
|
||||
## 外部后端实现核对结论(只分析,不改代码)
|
||||
|
||||
以下结论来自对 `GroupSideProjectManagementSystem` 后端 `third-v2` 路由、schema、operation、service 的实现阅读。
|
||||
|
||||
### 1) company 名称字段为何会空
|
||||
|
||||
- `/company/list` 并非直接返回库里的 `city_name/province_name/parent_name`,而是服务层在查询后“二次计算”这三个字段。
|
||||
- 计算依赖两张映射:
|
||||
- 行政区映射(`province/city code -> name`)
|
||||
- 公司映射(`parent_id -> parent_name`)
|
||||
- 如果编码不在映射中、或 `parent_id` 未命中,最终会返回 `None`/空字符串。
|
||||
- 因此该类差异并不一定是“推送失败”,更像是“回读时依赖映射补全失败或口径不一致”。
|
||||
|
||||
### 2) construction_task/material 的 plan_node 差异为何顽固
|
||||
|
||||
- 在 `third-v2` 的 `PlanUpdate` schema 中,存在 `model_validator`:会先自动清理边界节点(等于 `plan_start_date` 或 `plan_complete_date` 的首尾节点)。
|
||||
- 随后在 operation 的 `push(plan)` 中,又会把边界节点重新插回库里,并且统一写入 `is_audit=True`。
|
||||
- 这意味着:
|
||||
- 请求入参和最终落库结构并不完全一致;
|
||||
- 如果本地源数据不含边界节点,或 `is_audit` 口径不同,post-check 很容易出现稳定残差。
|
||||
|
||||
### 3) contract_settlement 为何最严重(34/34 + 8条失败)
|
||||
|
||||
- 计划更新接口的业务规则是“开始时间与合同金额来自合同表”,不是来自推送体:
|
||||
- `plan_start_date` 强制取合同 `sign_date`
|
||||
- `contract_price` 强制取合同 `total_price`
|
||||
- 即便推送体带了这两个值,也会在 operation 中被覆盖。
|
||||
- 同时仍有严格校验:计划节点必须晚于开始时间、早于结束时间、数量递增等;不满足直接 400。
|
||||
- 这正对应日志里的 8 条失败(计划节点时间校验)与大量更新后不一致(字段被后端覆盖到“合同口径”)。
|
||||
|
||||
### 4) list 回读与单条回读口径不一致(会放大不一致)
|
||||
|
||||
- 多个类型的 `get_by_id` 会裁掉 `plan_node` 首尾节点,但 `get_list_by_project_id` 通常返回主表原始节点(含首尾)。
|
||||
- 同步系统做 post-check 用的是 list 拉取结果时,这种“单条/列表口径不一致”会放大 plan_node 相关差异。
|
||||
|
||||
### 5) status/complete_rate/delay_days 等字段为何容易残留差异
|
||||
|
||||
- 这些字段主要由明细驱动的主表同步逻辑计算并回写,不是 plan/base update 的直接输入字段。
|
||||
- 因此“推送成功”并不等价于“这些派生字段立即与源数据一致”。
|
||||
|
||||
## 建议(仍不改代码)
|
||||
|
||||
1. **先按后端口径预处理结算计划数据**
|
||||
- 以合同 `sign_date/total_price` 作为 settlement 比对基准和推送基准;
|
||||
- 推送前先做节点时间边界校验,避免 400。
|
||||
|
||||
2. **对 plan_node 建立统一比较口径**
|
||||
- 在 post-check 里对 construction/material/settlement 统一做“边界节点归一化 + `is_audit` 口径归一化”后再比较。
|
||||
|
||||
3. **区分“业务真差异”与“后端派生差异”**
|
||||
- 对 `status/complete_rate/delay_days/actual_*` 这类派生字段设为可选比对或延迟比对。
|
||||
|
||||
4. **company 名称字段先做映射可用性核查**
|
||||
- 重点核对 `province/city` 编码是否在后端行政区字典可解析、`parent_id` 是否可命中公司映射。
|
||||
@@ -0,0 +1 @@
|
||||
{"_id": "a1d69bf1-b95e-4832-9258-5bc35c629e9a", "_rev": "2-e265a6cb3674c71d6957883177b270cb", "type": "company", "name": "金上公司", "short_name": "金上公司", "code": "028B", "company_type": "region", "parent_id": "5da30aa7-b560-416e-9223-284290692351", "path": ["5da30aa7-b560-416e-9223-284290692351", "a1d69bf1-b95e-4832-9258-5bc35c629e9a"], "path_name": ["集团公司", "金上公司"], "province": "510000", "city": "510100", "status": "active", "sort": 27, "created_by": "system", "created_by_name": "system", "created_at": "2025-05-30 09:00:09", "updated_by": "system", "updated_by_name": "system", "updated_at": "2025-09-25 20:08:42", "company_nature": ["owner"], "id": "a1d69bf1-b95e-4832-9258-5bc35c629e9a", "credit_code": null, "city_name": "成都市", "province_name": "四川省", "parent_name": "集团公司"}
|
||||
@@ -0,0 +1,63 @@
|
||||
{"_id": "020a3d53-4e45-4133-9e6e-93debd3dec22", "_rev": "9-3863902be07ce5855927de1726d5655a", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "825adfd5-02bb-422f-83bb-5543489c7e4d", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "825adfd5-02bb-422f-83bb-5543489c7e4d"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "825adfd5-02bb-422f-83bb-5543489c7e4d"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "825adfd5-02bb-422f-83bb-5543489c7e4d"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "进厂交通洞开挖(方)", "construction_section": "TJ", "status": 1, "task_type": "jcjtdkw", "plan_start_date": "2020-11-01", "plan_complete_date": "2021-07-31", "actual_complete_date": "2021-06-18", "complete_quantity": 24000.0, "complete_rate": 100.0, "contract_quantity": 24000.0, "plan_node": [{"date": "2020-11-01", "quantity": 0.0, "is_audit": false}, {"date": "2021-07-31", "quantity": 24000.0, "is_audit": false}], "statistic_date": "2021-06-18", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "126c3bdc-bcbf-4c65-a7e7-1d3b7e8e983c", "_rev": "5-1deb794b8c03770a6bdd95d8dd0b16a7", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "61c3e3b2-7529-4fff-80c3-c69c3ea4f9ad", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "61c3e3b2-7529-4fff-80c3-c69c3ea4f9ad"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "61c3e3b2-7529-4fff-80c3-c69c3ea4f9ad"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "61c3e3b2-7529-4fff-80c3-c69c3ea4f9ad"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "54ffaa56-529e-43ae-a8bc-28ab4f71b9e4", "show_name": "导流洞衬砌(米)", "construction_section": "TJ", "status": -1, "task_type": "dldcq", "plan_start_date": "2017-12-01", "plan_complete_date": "2018-04-15", "actual_complete_date": "2019-03-30", "complete_quantity": 1863.95, "complete_rate": 100.0, "contract_quantity": 1863.95, "plan_node": [{"date": "2017-12-01", "quantity": 0.0, "is_audit": false}, {"date": "2018-04-15", "quantity": 1863.95, "is_audit": false}], "statistic_date": "2019-03-30", "sort": 0, "is_crucial": false, "delay_days": 349}
|
||||
{"_id": "172c6a77-fd02-4cc6-b330-48bc9e67cfaa", "_rev": "7-35de25639a0be9cee9d3137c1bf3be60", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "57236743-c263-4171-af23-7ce7fd24bb77", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "57236743-c263-4171-af23-7ce7fd24bb77"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "57236743-c263-4171-af23-7ce7fd24bb77"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "57236743-c263-4171-af23-7ce7fd24bb77"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "4ab0bb83-64f7-4b64-96d6-907c843b7639", "show_name": "大坝基础开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "dbjckw", "plan_start_date": "2020-12-26", "plan_complete_date": "2021-06-30", "actual_complete_date": "2022-07-15", "complete_quantity": 882146.0, "complete_rate": 100.0, "contract_quantity": 882146.0, "plan_node": [{"date": "2020-12-26", "quantity": 0.0, "is_audit": false}, {"date": "2021-06-30", "quantity": 882146.0, "is_audit": false}], "statistic_date": "2022-07-15", "sort": 0, "is_crucial": false, "delay_days": 380}
|
||||
{"_id": "1961974f-e16a-4b7c-8388-edd80fe8a69d", "_rev": "8-6002b6008880fe052a5c9c8b9625e0a4", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "496a6abd-06c5-46fd-9b54-6195d81c741f", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "496a6abd-06c5-46fd-9b54-6195d81c741f"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "496a6abd-06c5-46fd-9b54-6195d81c741f"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "496a6abd-06c5-46fd-9b54-6195d81c741f"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "厂房开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "cfkw", "plan_start_date": "2020-04-01", "plan_complete_date": "2023-01-31", "actual_complete_date": "2023-05-28", "complete_quantity": 362300.0, "complete_rate": 100.0, "contract_quantity": 362300.0, "plan_node": [{"date": "2020-04-01", "quantity": 0.0, "is_audit": false}, {"date": "2020-12-31", "quantity": 107300.0, "is_audit": false}, {"date": "2021-06-30", "quantity": 172200.0, "is_audit": false}, {"date": "2022-01-15", "quantity": 214000.0, "is_audit": false}, {"date": "2022-07-15", "quantity": 273100.0, "is_audit": false}, {"date": "2022-10-31", "quantity": 332500.0, "is_audit": false}, {"date": "2023-01-31", "quantity": 362300.0, "is_audit": false}], "statistic_date": "2023-05-28", "sort": 0, "is_crucial": false, "delay_days": 117}
|
||||
{"_id": "240e5ae8-b3de-4684-abc1-d84283842ee4", "_rev": "4-0e110488d71e5ce3e41cef7f7d1dd2df", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "43db79ce-ce9c-4755-b4b6-16f5e239ee94", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "43db79ce-ce9c-4755-b4b6-16f5e239ee94"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "43db79ce-ce9c-4755-b4b6-16f5e239ee94"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "43db79ce-ce9c-4755-b4b6-16f5e239ee94"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": null, "show_name": "架线放线(⽶)", "construction_section": "SCDW", "status": 1, "task_type": "jxfxdw", "plan_start_date": "2025-09-01", "plan_complete_date": "2025-10-31", "actual_complete_date": "2025-10-28", "complete_quantity": 12166.0, "complete_rate": 100.0, "contract_quantity": 12166.0, "plan_node": [{"date": "2025-09-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-10-31", "quantity": 12166.0, "is_audit": false}], "statistic_date": "2025-10-28", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "26086ea8-9802-449a-929f-8712639c0090", "_rev": "5-6b93330392aaddfecf2d6a1807cb5faf", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "ab06caf1-608b-452c-b3ca-0e24d250f95d", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "ab06caf1-608b-452c-b3ca-0e24d250f95d"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "ab06caf1-608b-452c-b3ca-0e24d250f95d"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "ab06caf1-608b-452c-b3ca-0e24d250f95d"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "2e7feb46-667b-4b40-be23-f4f5589f0492", "show_name": "桥式起重设备(台)", "construction_section": "JSJG", "status": 1, "task_type": "qsqzsb", "plan_start_date": "2025-01-01", "plan_complete_date": "2025-06-30", "actual_complete_date": "2025-06-10", "complete_quantity": 2.0, "complete_rate": 100.0, "contract_quantity": 2.0, "plan_node": [{"date": "2025-01-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-06-30", "quantity": 2.0, "is_audit": false}], "statistic_date": "2025-06-10", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "3592d29c-b176-4e0c-8f4a-89cf5f685a3c", "_rev": "58-5adc52ea100296222833ebdd4547111d", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "981264e5-2798-4b1d-9854-b7226fa12248", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "981264e5-2798-4b1d-9854-b7226fa12248"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "981264e5-2798-4b1d-9854-b7226fa12248"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "981264e5-2798-4b1d-9854-b7226fa12248"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "发电机出口断路器安装(套)", "construction_section": "JD", "status": -1, "task_type": "fdjckdlqaz", "plan_start_date": "2025-09-01", "plan_complete_date": "2026-04-30", "actual_complete_date": null, "complete_quantity": 3.0, "complete_rate": 50.0, "contract_quantity": 6.0, "plan_node": [{"date": "2025-09-01", "quantity": 0.0, "is_audit": false}, {"date": "2026-04-30", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-11-15", "sort": 0, "is_crucial": false, "delay_days": 52}
|
||||
{"_id": "35ae3546-f018-4be0-9bf3-72b36b3dcdc7", "_rev": "7-9fc2c99df8d1ca862c0505ef5a3cb6a8", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "5f4515b4-ad9f-42a7-bb88-fdb8eaead4c5", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "5f4515b4-ad9f-42a7-bb88-fdb8eaead4c5"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "5f4515b4-ad9f-42a7-bb88-fdb8eaead4c5"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "5f4515b4-ad9f-42a7-bb88-fdb8eaead4c5"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "54ffaa56-529e-43ae-a8bc-28ab4f71b9e4", "show_name": "导流洞开挖(米)", "construction_section": "TJ", "status": -1, "task_type": "dldkw", "plan_start_date": "2017-02-10", "plan_complete_date": "2017-11-05", "actual_complete_date": "2017-11-28", "complete_quantity": 1863.95, "complete_rate": 100.0, "contract_quantity": 1863.95, "plan_node": [{"date": "2017-02-10", "quantity": 0.0, "is_audit": false}, {"date": "2017-11-05", "quantity": 1863.95, "is_audit": false}], "statistic_date": "2017-11-28", "sort": 0, "is_crucial": false, "delay_days": 23}
|
||||
{"_id": "3ca28f12-313a-405c-a7df-64e2b2630e61", "_rev": "5-2618d7356992f18412fac0f63fbc84c6", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "277f8dd2-363a-46d7-b3a6-6047f0199667", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "277f8dd2-363a-46d7-b3a6-6047f0199667"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "277f8dd2-363a-46d7-b3a6-6047f0199667"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "277f8dd2-363a-46d7-b3a6-6047f0199667"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "进厂交通洞衬砌(方)", "construction_section": "TJ", "status": 1, "task_type": "jcjtdcq", "plan_start_date": "2023-12-01", "plan_complete_date": "2024-03-31", "actual_complete_date": "2024-03-25", "complete_quantity": 6000.0, "complete_rate": 100.0, "contract_quantity": 6000.0, "plan_node": [{"date": "2023-12-01", "quantity": 0.0, "is_audit": false}, {"date": "2024-03-31", "quantity": 6000.0, "is_audit": false}], "statistic_date": "2024-03-25", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "53b44124-0f43-43bb-863d-fab0620bd3e8", "_rev": "98-01009e49cbea34229947594cab151f47", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "f0587ba5-4fa3-4182-ac3f-692cb29e1fe0", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "f0587ba5-4fa3-4182-ac3f-692cb29e1fe0"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "f0587ba5-4fa3-4182-ac3f-692cb29e1fe0"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "f0587ba5-4fa3-4182-ac3f-692cb29e1fe0"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "调速器及辅设安装(套)", "construction_section": "JD", "status": -1, "task_type": "tsqaz", "plan_start_date": "2025-08-01", "plan_complete_date": "2026-06-30", "actual_complete_date": null, "complete_quantity": 2.0, "complete_rate": 33.33, "contract_quantity": 6.0, "plan_node": [{"date": "2025-08-01", "quantity": 0.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-11-15", "sort": 0, "is_crucial": false, "delay_days": 93}
|
||||
{"_id": "54217b3b-ba7c-43c5-9ca5-8ac8eaca0974", "_rev": "48-d3883e56efdeafc63ffa8e2992eb9c53", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "39a75289-cff2-453b-8025-0d6a6749ac5b", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "39a75289-cff2-453b-8025-0d6a6749ac5b"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "39a75289-cff2-453b-8025-0d6a6749ac5b"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "39a75289-cff2-453b-8025-0d6a6749ac5b"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "主变压器安装(台)", "construction_section": "JD", "status": -1, "task_type": "zbazt", "plan_start_date": "2025-03-15", "plan_complete_date": "2026-03-31", "actual_complete_date": null, "complete_quantity": 5.0, "complete_rate": 83.33, "contract_quantity": 6.0, "plan_node": [{"date": "2025-03-15", "quantity": 0.0, "is_audit": false}, {"date": "2026-03-31", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-12-12", "sort": 0, "is_crucial": false, "delay_days": 15}
|
||||
{"_id": "6a1103ea-334f-41d7-8523-3e1d4fd99c06", "_rev": "9-69caaca99567888707dc9179439f79c5", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "approved", "approval_flow_id": "fc5cd0d4-881b-4b45-8a9a-ea2a80345019", "edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "fc5cd0d4-881b-4b45-8a9a-ea2a80345019"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "fc5cd0d4-881b-4b45-8a9a-ea2a80345019"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "fc5cd0d4-881b-4b45-8a9a-ea2a80345019"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "54ffaa56-529e-43ae-a8bc-28ab4f71b9e4", "show_name": "辅助工程施工及隧道衬砌(米)", "construction_section": "TJ", "status": 0, "task_type": "fzgcsgjsdcq", "plan_start_date": "2015-11-01", "plan_complete_date": "2019-07-18", "actual_complete_date": "2019-07-01", "complete_quantity": 45230.0, "complete_rate": 100.0, "contract_quantity": 45230.0, "plan_node": [{"date": "2015-11-01", "quantity": 0.0, "is_audit": true}, {"date": "2016-09-30", "quantity": 9170.0, "is_audit": true}, {"date": "2017-02-28", "quantity": 11435.0, "is_audit": true}, {"date": "2017-07-31", "quantity": 14898.0, "is_audit": true}, {"date": "2017-12-31", "quantity": 19304.0, "is_audit": true}, {"date": "2018-02-28", "quantity": 21014.0, "is_audit": true}, {"date": "2018-06-22", "quantity": 27254.0, "is_audit": true}, {"date": "2018-12-31", "quantity": 37472.0, "is_audit": true}, {"date": "2019-07-01", "quantity": 45000.0, "is_audit": true}, {"date": "2019-07-18", "quantity": 45230.0, "is_audit": true}], "statistic_date": "2019-07-01", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "78d7ab73-4e55-46fa-a208-1a21656cfa01", "_rev": "111-025c371931ae5a472de3d98186bb421c", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "dcb748dd-e67d-429d-9519-da39a188c229", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "dcb748dd-e67d-429d-9519-da39a188c229"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "dcb748dd-e67d-429d-9519-da39a188c229"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "dcb748dd-e67d-429d-9519-da39a188c229"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:43", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "发电机安装(台)", "construction_section": "JD", "status": -1, "task_type": "fdjaz", "plan_start_date": "2024-10-30", "plan_complete_date": "2026-12-31", "actual_complete_date": null, "complete_quantity": 3.0, "complete_rate": 50.0, "contract_quantity": 6.0, "plan_node": [{"date": "2024-10-30", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-12-31", "sort": 0, "is_crucial": false, "delay_days": 69}
|
||||
{"_id": "7c85896e-34c8-46a2-8e42-c93034d20805", "_rev": "6-ad00eb92f4055034c68f3be62fd6dd64", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "c7e31bc1-5cc7-4e51-b7b7-d84c88442ff5", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "c7e31bc1-5cc7-4e51-b7b7-d84c88442ff5"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "c7e31bc1-5cc7-4e51-b7b7-d84c88442ff5"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "c7e31bc1-5cc7-4e51-b7b7-d84c88442ff5"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": null, "show_name": "⽴塔(基)", "construction_section": "SCDW", "status": 1, "task_type": "ltdw", "plan_start_date": "2025-07-01", "plan_complete_date": "2025-10-31", "actual_complete_date": "2025-10-06", "complete_quantity": 21.0, "complete_rate": 100.0, "contract_quantity": 21.0, "plan_node": [{"date": "2025-07-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-10-31", "quantity": 21.0, "is_audit": false}], "statistic_date": "2025-10-06", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "_rev": "17-70d8d34a47e3801e14c940550a608e7a", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "8d9e943c-c29e-4280-b0cd-983312cb9ff1", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "8d9e943c-c29e-4280-b0cd-983312cb9ff1"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "8d9e943c-c29e-4280-b0cd-983312cb9ff1"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "8d9e943c-c29e-4280-b0cd-983312cb9ff1"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-07 00:00:41", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "4ab0bb83-64f7-4b64-96d6-907c843b7639", "show_name": "大坝坝体填/浇筑(方)", "construction_section": "TJ", "status": -1, "task_type": "dbbttz", "plan_start_date": "2022-08-11", "plan_complete_date": "2025-12-31", "actual_complete_date": "2026-02-01", "complete_quantity": 2630000.0, "complete_rate": 100.0, "contract_quantity": 2630000.0, "plan_node": [{"date": "2022-08-11", "quantity": 0.0, "is_audit": false}, {"date": "2025-12-31", "quantity": 2630000.0, "is_audit": false}], "statistic_date": "2026-02-01", "sort": 0, "is_crucial": false, "delay_days": 32}
|
||||
{"_id": "82990141-48ec-4101-942b-e27992e8b8f6", "_rev": "5-7f9ae0dfd5376eeec57514c4115b19d0", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "841c734c-02fc-47e8-86f0-5e2cc24aa0c9", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "841c734c-02fc-47e8-86f0-5e2cc24aa0c9"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "841c734c-02fc-47e8-86f0-5e2cc24aa0c9"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "841c734c-02fc-47e8-86f0-5e2cc24aa0c9"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "GIS安装(套)", "construction_section": "JD", "status": 1, "task_type": "gisazt", "plan_start_date": "2025-05-20", "plan_complete_date": "2025-10-31", "actual_complete_date": "2025-10-15", "complete_quantity": 1.0, "complete_rate": 100.0, "contract_quantity": 1.0, "plan_node": [{"date": "2025-05-20", "quantity": 0.0, "is_audit": false}, {"date": "2025-10-31", "quantity": 1.0, "is_audit": false}], "statistic_date": "2025-10-15", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "90f86791-0d3b-49e7-b7b9-90622ed9498d", "_rev": "7-74b5a400f27bbf6dbde08b66de3fa9a1", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "c8f242ab-4af0-4766-8229-d62b2757c513", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "c8f242ab-4af0-4766-8229-d62b2757c513"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "c8f242ab-4af0-4766-8229-d62b2757c513"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "c8f242ab-4af0-4766-8229-d62b2757c513"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "尾水隧洞衬砌(方)", "construction_section": "TJ", "status": 0, "task_type": "wssdcq", "plan_start_date": "2022-03-01", "plan_complete_date": "2024-12-31", "actual_complete_date": "2024-11-30", "complete_quantity": 271573.0, "complete_rate": 100.0, "contract_quantity": 271573.0, "plan_node": [{"date": "2022-03-01", "quantity": 0.0, "is_audit": false}, {"date": "2024-12-31", "quantity": 271573.0, "is_audit": false}], "statistic_date": "2024-11-30", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "924a3fa5-9487-4a72-8ad6-be1ba5cd671f", "_rev": "5-28fedd5a647881d4105a9fdd25d38bae", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "08983dc0-f9aa-4f66-94e5-7c33dfc12a39", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "08983dc0-f9aa-4f66-94e5-7c33dfc12a39"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "08983dc0-f9aa-4f66-94e5-7c33dfc12a39"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "08983dc0-f9aa-4f66-94e5-7c33dfc12a39"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "闸门及拦污栅安装(扇)", "construction_section": "JSJG", "status": 0, "task_type": "zmjlwsaz", "plan_start_date": "2025-01-01", "plan_complete_date": "2025-09-30", "actual_complete_date": "2025-09-28", "complete_quantity": 20.0, "complete_rate": 100.0, "contract_quantity": 20.0, "plan_node": [{"date": "2025-01-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 20.0, "is_audit": false}], "statistic_date": "2025-09-28", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "98c0b41a-b238-49cd-9d49-76ca8535a084", "_rev": "34-bc3433d0a2d2d1889a7235ceb3583de7", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "b7dd2ba3-248a-4c2b-8c44-de0a43c16795", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "b7dd2ba3-248a-4c2b-8c44-de0a43c16795"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "b7dd2ba3-248a-4c2b-8c44-de0a43c16795"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "b7dd2ba3-248a-4c2b-8c44-de0a43c16795"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "励磁系统安装及调试(套)", "construction_section": "JD", "status": -1, "task_type": "lcxtaz", "plan_start_date": "2025-08-01", "plan_complete_date": "2026-12-31", "actual_complete_date": null, "complete_quantity": 2.0, "complete_rate": 33.33, "contract_quantity": 6.0, "plan_node": [{"date": "2025-08-01", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-11-15", "sort": 0, "is_crucial": false, "delay_days": 29}
|
||||
{"_id": "9d1473b4-bc56-435d-b5e3-6f21f3413ec3", "_rev": "5-bcfe3571ca395f923e1ab30aba40d29a", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "4e7da869-9995-4e7d-9b34-46996405a466", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "4e7da869-9995-4e7d-9b34-46996405a466"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "4e7da869-9995-4e7d-9b34-46996405a466"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "4e7da869-9995-4e7d-9b34-46996405a466"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "2e7feb46-667b-4b40-be23-f4f5589f0492", "show_name": "液压式启闭机(台)", "construction_section": "JSJG", "status": 1, "task_type": "yysqbj", "plan_start_date": "2025-07-01", "plan_complete_date": "2025-09-30", "actual_complete_date": "2025-09-25", "complete_quantity": 6.0, "complete_rate": 100.0, "contract_quantity": 6.0, "plan_node": [{"date": "2025-07-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-09-25", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "a5702c85-eeaa-4253-a7b1-d434fb487e1e", "_rev": "10-cde2b68feac67ca275681fce3198bda4", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "e0538ab0-f7c6-432f-a559-5604252c686d", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "e0538ab0-f7c6-432f-a559-5604252c686d"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "e0538ab0-f7c6-432f-a559-5604252c686d"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "e0538ab0-f7c6-432f-a559-5604252c686d"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "厂房混凝土浇筑(方)", "construction_section": "TJ", "status": 0, "task_type": "cfhntjz", "plan_start_date": "2021-07-01", "plan_complete_date": "2025-07-31", "actual_complete_date": "2025-06-30", "complete_quantity": 121500.0, "complete_rate": 100.0, "contract_quantity": 121500.0, "plan_node": [{"date": "2021-07-01", "quantity": 0.0, "is_audit": false}, {"date": "2021-10-31", "quantity": 3670.0, "is_audit": false}, {"date": "2024-05-31", "quantity": 38760.0, "is_audit": false}, {"date": "2024-09-15", "quantity": 60420.0, "is_audit": false}, {"date": "2024-12-31", "quantity": 89600.0, "is_audit": false}, {"date": "2025-07-31", "quantity": 121500.0, "is_audit": false}], "statistic_date": "2025-06-30", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "c36ba699-de84-4439-90f3-8d71635c3c83", "_rev": "75-f614768562e84248c5f41b1c9f17cc0d", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "cf248d04-989c-4be3-a94c-78d1afee3d54", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "cf248d04-989c-4be3-a94c-78d1afee3d54"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "cf248d04-989c-4be3-a94c-78d1afee3d54"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "cf248d04-989c-4be3-a94c-78d1afee3d54"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:43", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "show_name": "水轮机安装(台)", "construction_section": "JD", "status": -1, "task_type": "sljaz", "plan_start_date": "2024-10-30", "plan_complete_date": "2026-12-31", "actual_complete_date": null, "complete_quantity": 3.0, "complete_rate": 50.0, "contract_quantity": 6.0, "plan_node": [{"date": "2024-10-30", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 6.0, "is_audit": false}], "statistic_date": "2025-11-15", "sort": 0, "is_crucial": false, "delay_days": 69}
|
||||
{"_id": "c512dc45-0505-49f5-b65c-b86878b185c3", "_rev": "20-0c73e5b8d9b9b22d64c8a06cea6fd5c3", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "approved", "approval_flow_id": "81aaf29d-2966-4fdc-bd7b-6e80622d57b1", "edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "81aaf29d-2966-4fdc-bd7b-6e80622d57b1"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "81aaf29d-2966-4fdc-bd7b-6e80622d57b1"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "81aaf29d-2966-4fdc-bd7b-6e80622d57b1"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "54ffaa56-529e-43ae-a8bc-28ab4f71b9e4", "show_name": "辅助工程开挖(米)", "construction_section": "TJ", "status": 0, "task_type": "fzgckw", "plan_start_date": "2015-11-01", "plan_complete_date": "2019-07-18", "actual_complete_date": "2019-07-01", "complete_quantity": 28374.0, "complete_rate": 100.0, "contract_quantity": 28374.0, "plan_node": [{"date": "2015-11-01", "quantity": 0.0, "is_audit": true}, {"date": "2016-09-30", "quantity": 690.0, "is_audit": true}, {"date": "2017-02-28", "quantity": 2333.0, "is_audit": true}, {"date": "2017-07-31", "quantity": 5408.0, "is_audit": true}, {"date": "2017-12-31", "quantity": 9730.0, "is_audit": true}, {"date": "2018-02-28", "quantity": 10790.0, "is_audit": true}, {"date": "2018-03-30", "quantity": 12320.0, "is_audit": true}, {"date": "2018-04-30", "quantity": 13520.0, "is_audit": true}, {"date": "2018-06-22", "quantity": 15920.0, "is_audit": true}, {"date": "2018-12-31", "quantity": 21699.0, "is_audit": true}, {"date": "2019-04-30", "quantity": 26733.0, "is_audit": true}, {"date": "2019-07-18", "quantity": 28374.0, "is_audit": true}], "statistic_date": "2019-07-01", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "c5ce2863-2e53-45bc-9d96-ef7f4b6d50e1", "_rev": "8-cf9e9415d4691fab8923c1d4cd106200", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "fedcec76-bd89-4b80-bcf7-b9a953df1bfa", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "fedcec76-bd89-4b80-bcf7-b9a953df1bfa"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "fedcec76-bd89-4b80-bcf7-b9a953df1bfa"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "fedcec76-bd89-4b80-bcf7-b9a953df1bfa"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": null, "show_name": "塔基(基)", "construction_section": "SCDW", "status": 1, "task_type": "tjdw", "plan_start_date": "2025-05-10", "plan_complete_date": "2025-08-31", "actual_complete_date": "2025-08-24", "complete_quantity": 21.0, "complete_rate": 100.0, "contract_quantity": 21.0, "plan_node": [{"date": "2025-05-10", "quantity": 0.0, "is_audit": false}, {"date": "2025-08-31", "quantity": 21.0, "is_audit": false}], "statistic_date": "2025-08-24", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "c6852b7c-5a91-444f-be24-615043c7add9", "_rev": "8-58b44dab6af8088ac175f6db4dabce1f", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "2df88e1f-d8cd-4355-afac-dae9990cccb6", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "2df88e1f-d8cd-4355-afac-dae9990cccb6"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "2df88e1f-d8cd-4355-afac-dae9990cccb6"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "2df88e1f-d8cd-4355-afac-dae9990cccb6"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "引水隧洞衬砌(方)", "construction_section": "TJ", "status": -1, "task_type": "yssdcq", "plan_start_date": "2022-05-01", "plan_complete_date": "2025-04-30", "actual_complete_date": "2025-11-30", "complete_quantity": 55242.0, "complete_rate": 100.0, "contract_quantity": 55242.0, "plan_node": [{"date": "2022-05-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-04-30", "quantity": 55242.0, "is_audit": false}], "statistic_date": "2025-11-30", "sort": 0, "is_crucial": false, "delay_days": 214}
|
||||
{"_id": "c8c6c5f8-f761-4e6e-baa1-636eba451873", "_rev": "33-4c5547262ef879fac818d16435706396", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "9e8fe87a-d57a-409d-ba6d-31502fd485b1", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "9e8fe87a-d57a-409d-ba6d-31502fd485b1"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "9e8fe87a-d57a-409d-ba6d-31502fd485b1"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "9e8fe87a-d57a-409d-ba6d-31502fd485b1"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "通风兼安全洞衬砌(方)", "construction_section": "TJ", "status": 0, "task_type": "jfjaqdcq", "plan_start_date": "2025-06-01", "plan_complete_date": "2025-12-31", "actual_complete_date": "2025-12-29", "complete_quantity": 6500.0, "complete_rate": 100.0, "contract_quantity": 6500.0, "plan_node": [{"date": "2025-06-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-12-31", "quantity": 6500.0, "is_audit": false}], "statistic_date": "2025-12-29", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "d051bad5-8958-46a9-937c-40e7c46e5592", "_rev": "5-71b37112bdae67bf01a9756df7f69a73", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "0dddf8d7-16eb-4865-a705-f68e673e4779", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "0dddf8d7-16eb-4865-a705-f68e673e4779"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "0dddf8d7-16eb-4865-a705-f68e673e4779"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "0dddf8d7-16eb-4865-a705-f68e673e4779"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "8db97a3a-be48-4ad9-957a-a67034eb99ed", "show_name": "鱼道工程(米)", "construction_section": "TJ", "status": 1, "task_type": "ydgc", "plan_start_date": "2024-09-01", "plan_complete_date": "2025-02-20", "actual_complete_date": "2025-01-05", "complete_quantity": 215.0, "complete_rate": 100.0, "contract_quantity": 215.0, "plan_node": [{"date": "2024-09-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-02-20", "quantity": 215.0, "is_audit": false}], "statistic_date": "2025-01-05", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "d5bee645-930c-4c80-8b2a-aee0e9f0dbff", "_rev": "5-4903694581c649858c042c414b83a0b9", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "17189da6-88da-48dd-adb7-125d5135391d", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "17189da6-88da-48dd-adb7-125d5135391d"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "17189da6-88da-48dd-adb7-125d5135391d"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "17189da6-88da-48dd-adb7-125d5135391d"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "引水隧洞开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "yssdkw", "plan_start_date": "2020-10-01", "plan_complete_date": "2022-07-31", "actual_complete_date": "2024-12-11", "complete_quantity": 222496.0, "complete_rate": 100.0, "contract_quantity": 222496.0, "plan_node": [{"date": "2020-10-01", "quantity": 0.0, "is_audit": false}, {"date": "2021-06-30", "quantity": 51700.0, "is_audit": false}, {"date": "2021-11-30", "quantity": 87647.0, "is_audit": false}, {"date": "2022-07-31", "quantity": 222496.0, "is_audit": false}], "statistic_date": "2024-12-11", "sort": 0, "is_crucial": false, "delay_days": 864}
|
||||
{"_id": "dc41afbc-c6d3-489d-8270-466349df0282", "_rev": "9-4df59b5e14bfdc1d0bcfbebaf70b5e2d", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "89ba6e79-7dca-47f5-8d54-918a6912f27f", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "89ba6e79-7dca-47f5-8d54-918a6912f27f"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "89ba6e79-7dca-47f5-8d54-918a6912f27f"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "89ba6e79-7dca-47f5-8d54-918a6912f27f"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "尾水隧洞开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "wssdkw", "plan_start_date": "2020-03-01", "plan_complete_date": "2022-12-31", "actual_complete_date": "2023-01-31", "complete_quantity": 6268.92, "complete_rate": 100.0, "contract_quantity": 6268.92, "plan_node": [{"date": "2020-03-01", "quantity": 0.0, "is_audit": false}, {"date": "2022-12-31", "quantity": 6268.92, "is_audit": false}], "statistic_date": "2023-01-31", "sort": 0, "is_crucial": false, "delay_days": 31}
|
||||
{"_id": "0200848d-d9e7-4372-a6f6-f768bac13955", "_rev": "1-fff3d992410dcecb499f14c0053ae256", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "主变压器安装(台)", "construction_section": "JD", "status": null, "task_type": "zbazt", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "13c53772-a5af-4a6f-a0fa-7a67d9254e46", "_rev": "6-7290bb2773b5292a126fa2355784290c", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "57cd2d1c-9bd8-4908-9db4-db7b89efbfe1", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "57cd2d1c-9bd8-4908-9db4-db7b89efbfe1"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "57cd2d1c-9bd8-4908-9db4-db7b89efbfe1"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "57cd2d1c-9bd8-4908-9db4-db7b89efbfe1"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "eba6d9e0-fad4-456d-a325-38f5bd064b33", "show_name": "引水隧洞衬砌(方)", "construction_section": "TJ", "status": 0, "task_type": "yssdcq", "plan_start_date": "2026-10-28", "plan_complete_date": "2029-07-08", "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 577073.0, "plan_node": [{"date": "2026-10-28", "quantity": 0.0, "is_audit": true}, {"date": "2029-07-08", "quantity": 577073.0, "is_audit": true}], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "13c6da7b-8963-4aba-9c79-883a340f21e7", "_rev": "9-ad06f47a01e37f107721afbc902e4844", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "afcd8026-d598-4220-a9b2-49df3d8e429c", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "afcd8026-d598-4220-a9b2-49df3d8e429c"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "afcd8026-d598-4220-a9b2-49df3d8e429c"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "afcd8026-d598-4220-a9b2-49df3d8e429c"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "eba6d9e0-fad4-456d-a325-38f5bd064b33", "show_name": "进厂交通洞开挖(方)", "construction_section": "TJ", "status": 1, "task_type": "jcjtdkw", "plan_start_date": "2025-01-01", "plan_complete_date": "2026-01-15", "actual_complete_date": "2025-11-18", "complete_quantity": 83935.0, "complete_rate": 100.0, "contract_quantity": 83935.0, "plan_node": [{"date": "2025-01-01", "quantity": 0.0, "is_audit": true}, {"date": "2026-01-15", "quantity": 83935.0, "is_audit": true}], "statistic_date": "2025-11-18", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "14ec3e17-0efc-47d7-8e1b-0f86478dd09a", "_rev": "1-ee61f54006d9ffaae0d71dbdd8dca279", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "架线放线(⽶)", "construction_section": "SCDW", "status": null, "task_type": "jxfxdw", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "4168d62e-8f4a-47d1-bb69-39b90e0b316d", "_rev": "1-c902561622de4582cdbe2545e8cca885", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "鱼道工程(米)", "construction_section": "TJ", "status": null, "task_type": "ydgc", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "48bea90d-8822-4a01-8ee5-77673351b3c7", "_rev": "1-cd4f61545f57bdf3c8d6a927d19fecc3", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "发电机出口断路器安装(套)", "construction_section": "JD", "status": null, "task_type": "fdjckdlqaz", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "4e584f84-4a68-4142-aea7-7204da39355e", "_rev": "1-bf936b5d2d05e075f914701a41a2c600", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "GIS安装(套)", "construction_section": "JD", "status": null, "task_type": "gisazt", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "5223a39e-1b46-43d4-9282-9becbfd8242c", "_rev": "1-24b76c3bd3e71b5476ceee8b3a9576b5", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "辅助工程开挖(米)", "construction_section": "TJ", "status": null, "task_type": "fzgckw", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "5bc1be87-64d7-4b7c-8c5d-973f83201f18", "_rev": "6-ba199edf39a4ddc0f9a073adf2ce733c", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "df1db0ab-fdfb-458f-86ff-54bcedf7981f", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "df1db0ab-fdfb-458f-86ff-54bcedf7981f"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "df1db0ab-fdfb-458f-86ff-54bcedf7981f"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "df1db0ab-fdfb-458f-86ff-54bcedf7981f"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "show_name": "大坝坝体填/浇筑(方)", "construction_section": "TJ", "status": 0, "task_type": "dbbttz", "plan_start_date": "2027-03-02", "plan_complete_date": "2028-05-02", "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 125090.0, "plan_node": [{"date": "2027-03-02", "quantity": 0.0, "is_audit": true}, {"date": "2028-05-02", "quantity": 125090.0, "is_audit": true}], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "62daee88-aa2e-4c80-aed7-234597b98873", "_rev": "50-6e1c8ff81ef75c1878108557ba44b591", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "8cc45de3-3549-41d5-a584-ca4eba240958", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "8cc45de3-3549-41d5-a584-ca4eba240958"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "8cc45de3-3549-41d5-a584-ca4eba240958"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "8cc45de3-3549-41d5-a584-ca4eba240958"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-02-27 00:00:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "3bb70c3c-f2e0-4763-a38e-35ef2937794e", "show_name": "厂房开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "cfkw", "plan_start_date": "2025-05-06", "plan_complete_date": "2027-08-15", "actual_complete_date": null, "complete_quantity": 71910.0, "complete_rate": 33.15, "contract_quantity": 216934.0, "plan_node": [{"date": "2025-05-06", "quantity": 0.0, "is_audit": true}, {"date": "2027-08-15", "quantity": 216934.0, "is_audit": true}], "statistic_date": "2026-01-29", "sort": 0, "is_crucial": false, "delay_days": 7}
|
||||
{"_id": "69826a7b-049e-493d-afc6-61d60d6da19c", "_rev": "6-c6556f637b9c2ba40c6ba7e1ad365e45", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "f787c8c4-a725-4dc5-b987-12f529ca94ce", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "f787c8c4-a725-4dc5-b987-12f529ca94ce"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "f787c8c4-a725-4dc5-b987-12f529ca94ce"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "f787c8c4-a725-4dc5-b987-12f529ca94ce"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "show_name": "大坝防渗工程(米)", "construction_section": "TJ", "status": 0, "task_type": "dbfsgc", "plan_start_date": "2026-12-15", "plan_complete_date": "2027-04-17", "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 6891.0, "plan_node": [{"date": "2026-12-15", "quantity": 0.0, "is_audit": true}, {"date": "2027-04-17", "quantity": 6891.0, "is_audit": true}], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "6ec1ba57-f677-4bf4-87ce-41e48c14a049", "_rev": "1-617cd121f6f96f4e872159fd14c911b0", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "发电机安装(台)", "construction_section": "JD", "status": null, "task_type": "fdjaz", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "732794c3-1efa-4b48-a901-ba150fa38679", "_rev": "2-b0ed6348507a862f8b0c7395e7ced324", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "eba6d9e0-fad4-456d-a325-38f5bd064b33", "show_name": "进厂交通洞衬砌(方)", "construction_section": "TJ", "status": null, "task_type": "jcjtdcq", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "75f5457c-8640-4868-8790-5b0571d14828", "_rev": "6-a8a3d1d77e710e990473f03655199e86", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "39c5af79-3fd5-4b90-b7ec-21fe96b4ab50", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "39c5af79-3fd5-4b90-b7ec-21fe96b4ab50"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "39c5af79-3fd5-4b90-b7ec-21fe96b4ab50"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "39c5af79-3fd5-4b90-b7ec-21fe96b4ab50"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "show_name": "大坝基础开挖(方)", "construction_section": "TJ", "status": 0, "task_type": "dbjckw", "plan_start_date": "2026-10-16", "plan_complete_date": "2026-12-14", "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 640807.0, "plan_node": [{"date": "2026-10-16", "quantity": 0.0, "is_audit": true}, {"date": "2026-12-14", "quantity": 640807.0, "is_audit": true}], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "8866cf58-e56a-49ff-8dae-245f234e48d5", "_rev": "1-2c90425f41ed2448c7b5fb95d952c1b6", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "塔基(基)", "construction_section": "SCDW", "status": null, "task_type": "tjdw", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "894f2bcb-39d2-4ecb-a101-19cd113c017e", "_rev": "1-19ce0c0b05ea31bdbcccefb72152d824", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "液压式启闭机(台)", "construction_section": "JSJG", "status": null, "task_type": "yysqbj", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "92c89e3b-fa1e-4496-9bf5-45124029c7cb", "_rev": "6-9ab6522e66020211f8d0e34edba888f3", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "4545d086-96a8-403b-815f-9179c7882df8", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "4545d086-96a8-403b-815f-9179c7882df8"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "4545d086-96a8-403b-815f-9179c7882df8"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "4545d086-96a8-403b-815f-9179c7882df8"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "3bb70c3c-f2e0-4763-a38e-35ef2937794e", "show_name": "尾水隧洞衬砌(方)", "construction_section": "TJ", "status": 0, "task_type": "wssdcq", "plan_start_date": "2026-09-16", "plan_complete_date": "2029-02-05", "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 54389.0, "plan_node": [{"date": "2026-09-16", "quantity": 0.0, "is_audit": true}, {"date": "2029-02-05", "quantity": 54389.0, "is_audit": true}], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "999ee29a-ae18-4e8a-999b-fafa98bd686f", "_rev": "1-2abe6eaab11f81e7934acc40bbefd5c4", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "通风兼安全洞开挖(方)", "construction_section": "TJ", "status": null, "task_type": "tfjaqdkw", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "9bdecd46-2c78-4c18-8af6-ed3d68b472c8", "_rev": "5-93f1ad253b96078e1262541e08166796", "field_metadata": {"plan_node": {"approval_status": "rejected", "approval_flow_id": "499c0a14-212c-4dca-a1b5-f422494ba709", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "rejected", "approval_flow_id": "499c0a14-212c-4dca-a1b5-f422494ba709"}, "plan_complete_date": {"approval_status": "rejected", "approval_flow_id": "499c0a14-212c-4dca-a1b5-f422494ba709"}, "contract_quantity": {"approval_status": "rejected", "approval_flow_id": "499c0a14-212c-4dca-a1b5-f422494ba709"}}, "approval_user": null, "approval_status": "rejected", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "3bb70c3c-f2e0-4763-a38e-35ef2937794e", "show_name": "厂房混凝土浇筑(方)", "construction_section": "TJ", "status": 0, "task_type": "cfhntjz", "plan_start_date": "2026-09-16", "plan_complete_date": "2029-02-05", "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 54389.0, "plan_node": [{"date": "2026-09-16", "quantity": 0.0, "is_audit": false}, {"date": "2029-02-05", "quantity": 54389.0, "is_audit": false}], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "a9eb5f17-35f0-44c1-a55b-0f3b4d91f843", "_rev": "1-d6ef0ab430dc886ca50dccd14152ea72", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "辅助工程施工及隧道衬砌(米)", "construction_section": "TJ", "status": null, "task_type": "fzgcsgjsdcq", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "c7729461-f85a-4fdb-8c08-b10581a0a226", "_rev": "1-37b070a8fd359267f5b8484fe4b398d9", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "调速器及辅设安装(套)", "construction_section": "JD", "status": null, "task_type": "tsqaz", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "_rev": "123-0080a27518b7766779de1def927f2149", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "361f1e7a-64f0-4ae8-b61f-f6edb535087d", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "361f1e7a-64f0-4ae8-b61f-f6edb535087d"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "361f1e7a-64f0-4ae8-b61f-f6edb535087d"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "361f1e7a-64f0-4ae8-b61f-f6edb535087d"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-02-27 00:00:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "eba6d9e0-fad4-456d-a325-38f5bd064b33", "show_name": "引水隧洞开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "yssdkw", "plan_start_date": "2025-01-01", "plan_complete_date": "2029-02-28", "actual_complete_date": null, "complete_quantity": 524122.0, "complete_rate": 15.15, "contract_quantity": 3458932.0, "plan_node": [{"date": "2025-01-01", "quantity": 0.0, "is_audit": true}, {"date": "2029-02-28", "quantity": 3458932.0, "is_audit": true}], "statistic_date": "2026-01-29", "sort": 0, "is_crucial": false, "delay_days": 180}
|
||||
{"_id": "d0e448b8-41f1-438e-9d4e-7392c8e90ee2", "_rev": "1-b229f36d804234cc7a4a05cfd90cdb51", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "水轮机安装(台)", "construction_section": "JD", "status": null, "task_type": "sljaz", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "db2651d7-f9a9-4e83-997e-5a0693c96190", "_rev": "1-5a7a72a6a1075e42afbb2602383222cb", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "⽴塔(基)", "construction_section": "SCDW", "status": null, "task_type": "ltdw", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "de5426b5-2e3d-4335-bd80-857c939ff5c0", "_rev": "1-3682684c8bfae8f47578501d7f5b5796", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "通风兼安全洞衬砌(方)", "construction_section": "TJ", "status": null, "task_type": "jfjaqdcq", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "e10d9b1a-ed23-4139-9930-61427e65fa48", "_rev": "9-94f4a033cb631072f83448db52342fbf", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "7ae0ef80-12e2-42ad-bda7-9e129c902323", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "7ae0ef80-12e2-42ad-bda7-9e129c902323"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "7ae0ef80-12e2-42ad-bda7-9e129c902323"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "7ae0ef80-12e2-42ad-bda7-9e129c902323"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "show_name": "导流洞开挖(米)", "construction_section": "TJ", "status": 0, "task_type": "dldkw", "plan_start_date": "2024-09-01", "plan_complete_date": "2025-04-30", "actual_complete_date": "2025-04-30", "complete_quantity": 672.0, "complete_rate": 100.0, "contract_quantity": 672.0, "plan_node": [{"date": "2024-09-01", "quantity": 0.0, "is_audit": true}, {"date": "2025-04-30", "quantity": 672.0, "is_audit": true}], "statistic_date": "2025-04-30", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "e4f61ce9-1e4f-4f94-9f62-c5464afbe1d5", "_rev": "1-642fe77d0ba5833b16d12e985b8e8c3c", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "卷扬式启闭机(台)", "construction_section": "JSJG", "status": null, "task_type": "jysqbj", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "934208de-1290-4840-9e7e-b957815b3743", "_rev": "6-c62b82de25b171d5890c719d4f08a0a8", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "approved", "approval_flow_id": "bc984077-20f5-495e-aafe-db719a5c1cec", "edit_after_approve": true}, "complete_rate": {}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "bc984077-20f5-495e-aafe-db719a5c1cec"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "bc984077-20f5-495e-aafe-db719a5c1cec"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "bc984077-20f5-495e-aafe-db719a5c1cec"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-09 23:09:16", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-09 23:09:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "show_name": "导流洞衬砌(米)", "construction_section": "TJ", "status": 1, "task_type": "dldcq", "plan_start_date": "2025-01-01", "plan_complete_date": "2025-09-15", "actual_complete_date": "2025-07-20", "complete_quantity": 28782.29, "complete_rate": 100.0, "contract_quantity": 28782.29, "plan_node": [{"date": "2025-01-01", "quantity": 0.0, "is_audit": true}, {"date": "2025-09-15", "quantity": 28782.29, "is_audit": true}], "statistic_date": "2025-07-20", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "ecb6a8a6-b28a-4a55-b1fe-0b5d59dc207e", "_rev": "9-86e8e89572a0e17c7cdbc5563b5f34d0", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "b9a98141-b786-4050-8a08-1147026fbc46", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "b9a98141-b786-4050-8a08-1147026fbc46"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "b9a98141-b786-4050-8a08-1147026fbc46"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "b9a98141-b786-4050-8a08-1147026fbc46"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "show_name": "通风兼安全洞开挖(方)", "construction_section": "TJ", "status": -1, "task_type": "tfjaqdkw", "plan_start_date": "2019-10-01", "plan_complete_date": "2022-01-31", "actual_complete_date": "2022-06-30", "complete_quantity": 118500.0, "complete_rate": 100.0, "contract_quantity": 118500.0, "plan_node": [{"date": "2019-10-01", "quantity": 0.0, "is_audit": false}, {"date": "2019-12-31", "quantity": 35300.0, "is_audit": false}, {"date": "2020-03-31", "quantity": 84800.0, "is_audit": false}, {"date": "2021-02-28", "quantity": 84810.0, "is_audit": false}, {"date": "2021-06-30", "quantity": 111500.0, "is_audit": false}, {"date": "2021-12-31", "quantity": 117200.0, "is_audit": false}, {"date": "2022-01-31", "quantity": 118500.0, "is_audit": false}], "statistic_date": "2022-06-30", "sort": 0, "is_crucial": false, "delay_days": 150}
|
||||
{"_id": "fc2b07bc-e85a-4762-9559-c16936b5b0d5", "_rev": "9-aaab2344ec3820ec69933b0b8fa81dc0", "field_metadata": {"is_crucial": {"edit_after_approve": true}, "plan_node": {"approval_status": "under_review", "approval_flow_id": "733bfaf9-9304-47fb-a89a-05a9f8325081", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "733bfaf9-9304-47fb-a89a-05a9f8325081"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "733bfaf9-9304-47fb-a89a-05a9f8325081"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "733bfaf9-9304-47fb-a89a-05a9f8325081"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "4ab0bb83-64f7-4b64-96d6-907c843b7639", "show_name": "大坝防渗工程(米)", "construction_section": "TJ", "status": 0, "task_type": "dbfsgc", "plan_start_date": "2021-03-16", "plan_complete_date": "2025-09-30", "actual_complete_date": "2025-09-25", "complete_quantity": 315800.0, "complete_rate": 100.0, "contract_quantity": 315800.0, "plan_node": [{"date": "2021-03-16", "quantity": 0.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 315800.0, "is_audit": false}], "statistic_date": "2025-09-25", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
{"_id": "f868d55b-6574-4a6b-9180-3a2962f8dc4c", "_rev": "1-70770a08951648221187df2d02944e04", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "励磁系统安装及调试(套)", "construction_section": "JD", "status": null, "task_type": "lcxtaz", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "f9894b7d-ef21-4f65-b59c-c4a71544bb1b", "_rev": "1-a77ad4553eb1333361abcfd94d85598e", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "闸门及拦污栅安装(扇)", "construction_section": "JSJG", "status": null, "task_type": "zmjlwsaz", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "fb9b02cd-b82c-4aa8-b475-5c3643d7e38e", "_rev": "1-dcb3d6fd7606b14995248f71798d593f", "field_metadata": {"plan_node": {"edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": null, "show_name": "桥式起重设备(台)", "construction_section": "JSJG", "status": null, "task_type": "qsqzsb", "plan_start_date": null, "plan_complete_date": null, "actual_complete_date": null, "complete_quantity": 0.0, "complete_rate": 0.0, "contract_quantity": 0.0, "plan_node": [], "statistic_date": null, "sort": 0, "is_crucial": false, "delay_days": null}
|
||||
{"_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "_rev": "14-0b500978a8e3d03ad7f29e8a15f4cbf1", "field_metadata": {"plan_node": {"approval_status": "approved", "approval_flow_id": "dfd3479f-d3ff-49a9-98ca-d1280214e6fd", "edit_after_approve": true}, "is_crucial": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "approved", "approval_flow_id": "dfd3479f-d3ff-49a9-98ca-d1280214e6fd"}, "plan_complete_date": {"approval_status": "approved", "approval_flow_id": "dfd3479f-d3ff-49a9-98ca-d1280214e6fd"}, "contract_quantity": {"approval_status": "approved", "approval_flow_id": "dfd3479f-d3ff-49a9-98ca-d1280214e6fd"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-01-29 21:32:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "3bb70c3c-f2e0-4763-a38e-35ef2937794e", "show_name": "尾水隧洞开挖(方)", "construction_section": "TJ", "status": 1, "task_type": "wssdkw", "plan_start_date": "2025-11-28", "plan_complete_date": "2029-03-08", "actual_complete_date": null, "complete_quantity": 29930.0, "complete_rate": 15.22, "contract_quantity": 196645.0, "plan_node": [{"date": "2025-11-28", "quantity": 0.0, "is_audit": true}, {"date": "2029-03-08", "quantity": 196645.0, "is_audit": true}], "statistic_date": "2026-01-29", "sort": 0, "is_crucial": false, "delay_days": 0}
|
||||
@@ -0,0 +1,87 @@
|
||||
{"_id": "4a880161-3207-405c-9a66-6a2ff716db49", "_rev": "4-50801a0460a099f3be45415ffd234317", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-09 23:05:08", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 11:16:17", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 11:16:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "16512636-e811-4f6f-823e-ec95b4b1d0dc", "rate": null, "quantity": 28782.29, "date": "2025-07-20", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "db98ec2d-1c6b-45f4-a176-7b560a8a89fe", "_rev": "2-c3fce218d5460d66a7c8335435342af2", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 20:21:22", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 11:44:50", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 11:44:50", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 297330.0, "date": "2025-11-08", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "144537c6-138e-4814-8d3c-6f583f78146b", "_rev": "2-ce218c11e1ec44b28b7aa143776a1d97", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 20:20:33", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 15:50:02", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 15:50:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 49030.0, "date": "2025-11-06", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "d952dcb3-05cb-4ec9-ab9c-785f9882cc76", "_rev": "2-0142fe981c773853d1daba34068dae02", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 20:22:27", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 15:53:37", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 15:53:37", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 4300.0, "date": "2025-11-06", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "7e2b3bf3-0e77-48db-868c-652384607504", "_rev": "2-8fb2780d1e1465621df4ca9a26ef62d9", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-10 15:50:53", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 16:25:53", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 16:25:53", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "13c6da7b-8963-4aba-9c79-883a340f21e7", "rate": null, "quantity": 81417.0, "date": "2025-11-06", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "050510ef-1a0e-409e-8444-a50ccdac6a51", "_rev": "1-e73fcf3b9fb36b3458626d15aa46f35e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-11 16:45:29", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-11 16:45:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "6a1103ea-334f-41d7-8523-3e1d4fd99c06", "rate": null, "quantity": 45230.0, "date": "2019-07-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "f12c9f08-5365-4f5a-a5eb-72d5f5ecf568", "_rev": "2-ccb2ab706bd84a2f03d07496d4ee491e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 10:06:04", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-11 21:20:22", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-11 21:20:22", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c512dc45-0505-49f5-b65c-b86878b185c3", "rate": null, "quantity": 28374.0, "date": "2019-07-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "497c8f5a-1bf8-447f-ab30-33c41465d15e", "_rev": "2-af3fb88178dbe8e518dbfbdb07f44526", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 09:57:54", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 09:53:54", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 09:53:54", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ecb6a8a6-b28a-4a55-b1fe-0b5d59dc207e", "rate": null, "quantity": 84800.0, "date": "2020-03-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "70b8e035-2ed4-46f3-b7b5-bc6b4841d5b5", "_rev": "4-8273c8b08a0dfc61ad099d6a81d8e585", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 10:05:25", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 09:58:36", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 09:58:36", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ecb6a8a6-b28a-4a55-b1fe-0b5d59dc207e", "rate": null, "quantity": 91500.0, "date": "2021-01-31", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "57957c02-e041-41bd-b209-ffe7a6e29b34", "_rev": "3-46ed22577c18f4a454c501228eda3a83", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 10:13:33", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 10:13:33", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ecb6a8a6-b28a-4a55-b1fe-0b5d59dc207e", "rate": null, "quantity": 118500.0, "date": "2022-06-30", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "9c91886e-de23-4eed-8f26-7d6cb3963578", "_rev": "1-e5c2c044cc6ff530850209542a41b775", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 10:35:32", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 10:35:32", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "020a3d53-4e45-4133-9e6e-93debd3dec22", "rate": null, "quantity": 24000.0, "date": "2021-06-18", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b47dbe74-67e3-426e-87e9-2e64c70bf09b", "_rev": "1-35e9f1e2004723bd522ece7f692b16c8", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 14:44:55", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 14:44:55", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "3ca28f12-313a-405c-a7df-64e2b2630e61", "rate": null, "quantity": 6000.0, "date": "2024-03-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "27f1c2bb-2c2c-4de6-8c1f-4a4b04b5d124", "_rev": "1-abc41cd9e7d2279fee55bd84c6ec5307", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 15:37:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 15:37:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "35ae3546-f018-4be0-9bf3-72b36b3dcdc7", "rate": null, "quantity": 1863.95, "date": "2017-11-28", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "fdf11fbf-c8ac-4575-a6f4-a61ba9d2bd30", "_rev": "1-b7dfa30b4fe195e57ec429a5ccdb7a62", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 15:39:35", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 15:39:35", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "126c3bdc-bcbf-4c65-a7e7-1d3b7e8e983c", "rate": null, "quantity": 1863.95, "date": "2019-03-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "33bedcdf-55af-476a-910f-c0eb89792c1b", "_rev": "3-bb6e294e3e1f131b067a3b2017c6d945", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 16:14:42", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 16:14:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "1961974f-e16a-4b7c-8388-edd80fe8a69d", "rate": null, "quantity": 362300.0, "date": "2023-05-28", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "e019c3bc-dc02-4825-ad95-fcc819e7ac86", "_rev": "2-376d3dbe9b01e74452e259d187f9b019", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 16:38:08", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 16:37:13", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 16:37:13", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "a5702c85-eeaa-4253-a7b1-d434fb487e1e", "rate": null, "quantity": 2404.0, "date": "2022-08-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "ee176983-e538-41e1-bc38-e697893ca415", "_rev": "2-c52913dcefe94b2ccd76fdbf5feb19a2", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 16:46:36", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 16:45:46", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 16:45:46", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "a5702c85-eeaa-4253-a7b1-d434fb487e1e", "rate": null, "quantity": 74500.0, "date": "2024-08-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "98bd3541-6589-45bf-af0b-9c4f619e65c3", "_rev": "2-5d47dba18421354980192fcc75bcfd2b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 16:48:21", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 16:47:43", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 16:47:43", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "a5702c85-eeaa-4253-a7b1-d434fb487e1e", "rate": null, "quantity": 109600.0, "date": "2024-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "20f18a6d-e21b-4c66-980b-d0c47b1318be", "_rev": "1-57ac720127fc9e2cbb2d11bd972ed556", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 16:49:08", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 16:49:08", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "a5702c85-eeaa-4253-a7b1-d434fb487e1e", "rate": null, "quantity": 121500.0, "date": "2025-06-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "8d46161f-ac07-440a-8bfc-9ecf4383da5b", "_rev": "2-41b785d62f57ac59b26338924e1186b8", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 20:18:00", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-13 16:50:15", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-13 16:50:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "e10d9b1a-ed23-4139-9930-61427e65fa48", "rate": null, "quantity": 672.0, "date": "2025-04-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "5f295f4e-4c9c-4fb9-97d6-305ebb900cfa", "_rev": "1-7f067aa6defcf997ceb406d57d57dfd9", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 17:03:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 17:03:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "d5bee645-930c-4c80-8b2a-aee0e9f0dbff", "rate": null, "quantity": 222496.0, "date": "2024-12-11", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "7e0aece9-5dbf-4fa9-98be-43ffe8891d57", "_rev": "2-5ab8c3884b8328660cf0b8d48c5fad88", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 17:19:40", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 17:17:27", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 17:17:27", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c6852b7c-5a91-444f-be24-615043c7add9", "rate": null, "quantity": 19300.0, "date": "2024-08-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "5cb48b1e-5e73-47fe-9f96-54bd725701dc", "_rev": "2-17958b46246ccd3c23deefac74760e96", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-13 17:23:29", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 17:20:14", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 17:20:14", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c6852b7c-5a91-444f-be24-615043c7add9", "rate": null, "quantity": 34200.0, "date": "2024-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "ffcf32f1-ebe9-444e-a662-4bc9a8ab2f1a", "_rev": "3-7d8b2e41ba7667440f6a21c14f9ee16d", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 17:34:34", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 17:34:34", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "172c6a77-fd02-4cc6-b330-48bc9e67cfaa", "rate": null, "quantity": 882146.0, "date": "2022-07-15", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "8c87e8da-0446-4cea-ac9b-5486b9c50d60", "_rev": "2-9f00705b3fd73dbbfbf5b6092c6abf57", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-03 10:38:51", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-13 21:10:31", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-13 21:10:31", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c6852b7c-5a91-444f-be24-615043c7add9", "rate": null, "quantity": 54300.0, "date": "2025-11-13", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "4555bf3a-634f-4c1f-9757-b03cf47b39a5", "_rev": "4-4f484726a4e3d11c9f30e084c04c507c", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 08:59:37", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 08:55:28", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 08:55:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 54000.0, "date": "2022-12-31", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "fd8d1d97-2089-46d8-b3ef-13ffcda36783", "_rev": "2-6b221d0a40c1d18a5e38558e97276b19", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 09:00:32", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 09:00:08", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 09:00:08", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 721000.0, "date": "2023-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "e4c3aeda-21b0-4634-a8a3-9ee3afa8d3b5", "_rev": "2-c00c157790d6b1c58b01ce73b9aa10cb", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 09:05:22", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 09:04:59", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 09:04:59", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 1830900.0, "date": "2024-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "f1fbf342-06d2-4f45-871a-5138bd511960", "_rev": "2-7af32f124e27b290b3ba165743315c1e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-03 10:39:07", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 09:05:36", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 09:05:36", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 2593200.0, "date": "2025-11-14", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "39a704d6-cad7-475b-9d76-50d13c50005e", "_rev": "2-6e81fcd6069c39d3503363f832a2731b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-09 16:19:22", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 09:16:43", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 09:16:43", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c8c6c5f8-f761-4e6e-baa1-636eba451873", "rate": null, "quantity": 5200.0, "date": "2025-11-14", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b0b39475-13f3-4a98-9649-24c7f5ada578", "_rev": "1-99840ae0fc5b83baab790f026739f758", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:08:11", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:08:11", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "dc41afbc-c6d3-489d-8270-466349df0282", "rate": null, "quantity": 6268.92, "date": "2023-01-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b3290933-3e0c-454d-bfd4-251cea5c6769", "_rev": "2-767475646f6cd8f2f33d66a357d8cb7e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 10:16:30", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:16:03", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:16:03", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "90f86791-0d3b-49e7-b7b9-90622ed9498d", "rate": null, "quantity": 65000.0, "date": "2022-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "8bdbb8be-bb75-4835-acf6-2d8b2687b554", "_rev": "2-f14456c40cfcd021e616e5011602483b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 10:17:44", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:17:24", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:17:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "90f86791-0d3b-49e7-b7b9-90622ed9498d", "rate": null, "quantity": 180900.0, "date": "2023-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "d395760f-90f9-40d9-a7cf-26f6148dfa24", "_rev": "2-25851905d8d9a861de4e8a98d695cec9", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 10:20:16", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:18:06", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:18:06", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "90f86791-0d3b-49e7-b7b9-90622ed9498d", "rate": null, "quantity": 271573.0, "date": "2024-11-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "0844c8dd-fe07-4472-ab0e-c4c0fd933066", "_rev": "2-5787d9ed6d720bc79a7fb9cf561b2053", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 10:35:34", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:32:58", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:32:58", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "fc2b07bc-e85a-4762-9559-c16936b5b0d5", "rate": null, "quantity": 69689.54, "date": "2023-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b40513ee-7bfa-4c79-a997-868410cd0b11", "_rev": "2-6d39450b1da2dd8a3aa6cb944da641f4", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 10:43:07", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:42:41", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:42:41", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "fc2b07bc-e85a-4762-9559-c16936b5b0d5", "rate": null, "quantity": 231800.0, "date": "2024-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "9b95817a-da37-4c95-9935-8289acc8fe5d", "_rev": "1-eb11d81df23edfef1ee680717f973d6b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:43:17", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:43:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "fc2b07bc-e85a-4762-9559-c16936b5b0d5", "rate": null, "quantity": 315800.0, "date": "2025-09-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b24517ce-5212-4272-bdd3-66abff123a35", "_rev": "1-fa8442c1742b8c0613b1004954d92e2b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 14:26:16", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 14:26:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "d051bad5-8958-46a9-937c-40e7c46e5592", "rate": null, "quantity": 215.0, "date": "2025-01-05", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "04dc2c7f-730f-4fb8-8d37-f8f79e015592", "_rev": "2-6318da8f87e69794c994904219450eea", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 15:24:59", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:24:28", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:24:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c5ce2863-2e53-45bc-9d96-ef7f4b6d50e1", "rate": null, "quantity": 5.0, "date": "2025-06-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "df42c876-0797-4792-9af1-8bcf024887d6", "_rev": "2-feb25ee11582178950b9b44ab017e537", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 15:25:40", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:25:19", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:25:19", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c5ce2863-2e53-45bc-9d96-ef7f4b6d50e1", "rate": null, "quantity": 17.0, "date": "2025-07-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "964ac118-0612-40a4-83dc-dbe31e59a1da", "_rev": "1-1c7e2eac244d51a2aa621caf25dfad74", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:26:51", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:26:51", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c5ce2863-2e53-45bc-9d96-ef7f4b6d50e1", "rate": null, "quantity": 21.0, "date": "2025-08-24", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "a7f7bd84-f7f2-40ef-8ba4-a8b983d26adf", "_rev": "2-d68a8921e55d676aead50b757bab111a", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 15:30:40", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:30:16", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:30:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7c85896e-34c8-46a2-8e42-c93034d20805", "rate": null, "quantity": 12.0, "date": "2025-08-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "ead52141-0182-4348-9f63-9d8c8a4e898e", "_rev": "2-5834b0265260b043cc3730bd539f4380", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-14 15:31:53", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:31:03", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:31:03", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7c85896e-34c8-46a2-8e42-c93034d20805", "rate": null, "quantity": 20.0, "date": "2025-09-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "f5ad4130-ee7b-4fd2-bd76-282dec1280d1", "_rev": "1-429b79de272b45bc3c1cce3b34195133", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:32:06", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:32:06", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7c85896e-34c8-46a2-8e42-c93034d20805", "rate": null, "quantity": 21.0, "date": "2025-10-06", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "5af5ee3b-cf7e-4a81-a16d-65378e73295c", "_rev": "1-6a9e4358961315a7803e24ba062d8264", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 15:48:39", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 15:48:39", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "240e5ae8-b3de-4684-abc1-d84283842ee4", "rate": null, "quantity": 12166.0, "date": "2025-10-28", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "57e96e42-5357-4772-b34b-e0406f0c0a9f", "_rev": "1-ec9dd01192c70c592d0471809dadd6b7", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 08:44:22", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 08:44:22", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "924a3fa5-9487-4a72-8ad6-be1ba5cd671f", "rate": null, "quantity": 20.0, "date": "2025-09-28", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "173843c5-46d8-467d-aa59-2db3bf1e8d3f", "_rev": "1-c340febe092bc261f00379ea9604f130", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 08:45:26", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 08:45:26", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "9d1473b4-bc56-435d-b5e3-6f21f3413ec3", "rate": null, "quantity": 6.0, "date": "2025-09-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "6a50b11a-8cd3-4b06-9c2d-a6e2e3ba3625", "_rev": "1-a08ed7bf11aab4d40a1c8a6dcc783e0e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 08:46:11", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 08:46:11", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "26086ea8-9802-449a-929f-8712639c0090", "rate": null, "quantity": 2.0, "date": "2025-06-10", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "3f870711-43f8-4905-98f0-370c28312083", "_rev": "2-9f80aea147af2b0fae67391bc6f153e0", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:06:08", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:27:25", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:27:25", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c36ba699-de84-4439-90f3-8d71635c3c83", "rate": null, "quantity": 3.0, "date": "2025-11-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "c34ac740-eb77-4b9b-8db8-0403f36b56ee", "_rev": "2-6c7870e07cb8fb7a09f323df0e87ab4f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:06:20", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:27:37", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:27:37", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "78d7ab73-4e55-46fa-a208-1a21656cfa01", "rate": null, "quantity": 2.0, "date": "2025-11-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "6d50c6c6-a92e-4023-88f7-46c8e4f5a3ba", "_rev": "2-68a001fbd7617d983f9a4df07b975a03", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:06:30", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:30:28", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:30:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "53b44124-0f43-43bb-863d-fab0620bd3e8", "rate": null, "quantity": 2.0, "date": "2025-11-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "f6d89bc5-e689-44cb-b0bf-16644374dee6", "_rev": "2-17cf56f3c65bd367ec5d46d7917efdcc", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:06:39", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:32:12", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:32:12", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "98c0b41a-b238-49cd-9d49-76ca8535a084", "rate": null, "quantity": 2.0, "date": "2025-11-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "2e994a81-cb40-41eb-b8fd-6c94a13d5aa7", "_rev": "1-40819cfdb44128c5eef63d5b3d353410", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:35:05", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:35:05", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "82990141-48ec-4101-942b-e27992e8b8f6", "rate": null, "quantity": 1.0, "date": "2025-10-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "53a5d03d-1cf8-4a46-ad12-b6f4b521d533", "_rev": "2-20ac0def1dfda97bcb467713c3e35d30", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:06:59", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:36:59", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:36:59", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "54217b3b-ba7c-43c5-9ca5-8ac8eaca0974", "rate": null, "quantity": 2.0, "date": "2025-11-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b6c70db5-554a-45f2-ac12-992e69ad3e11", "_rev": "2-9482384fa1ba7e42ccb9f793d5a875ae", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:06:48", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:38:33", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:38:33", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "3592d29c-b176-4e0c-8f4a-89cf5f685a3c", "rate": null, "quantity": 3.0, "date": "2025-11-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "e2633f28-0a4e-4376-831e-497cd8a074ce", "_rev": "1-7e0ce8804e7e5090c5fca9f0a346e98c", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-03 10:39:36", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-03 10:39:36", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c6852b7c-5a91-444f-be24-615043c7add9", "rate": null, "quantity": 55242.0, "date": "2025-11-30", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "cde82b83-e4d2-47f0-83c3-441de773c593", "_rev": "2-1ab3922ba3e09cdc263d4bda7d1ed2a9", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-29 11:16:23", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-04 09:49:47", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-04 09:49:47", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 2609300.0, "date": "2025-12-03", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "6d35330a-92e8-46b9-bb47-bcacdd2ce114", "_rev": "2-f914291dcf8a1390cb598488ec22d8a2", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-29 14:42:57", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:22:13", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:22:13", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c8c6c5f8-f761-4e6e-baa1-636eba451873", "rate": null, "quantity": 5700.0, "date": "2025-12-03", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "06787fe3-a77b-41a9-b51a-5d427b784708", "_rev": "2-c7b3280006bae174a7aeb53cff44e630", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-18 21:24:32", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-09 23:18:46", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-09 23:18:46", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "934208de-1290-4840-9e7e-b957815b3743", "rate": null, "quantity": 28782.29, "date": "2025-07-20", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "8cf98191-1a57-47ac-98e8-efd3d45208f1", "_rev": "1-d16b14645e1b7b5f68e3c98c21cbc641", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 17:25:36", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 17:25:36", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "54217b3b-ba7c-43c5-9ca5-8ac8eaca0974", "rate": null, "quantity": 5.0, "date": "2025-12-12", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "6d4b828b-fd29-4b6a-8622-4b681b58124c", "_rev": "2-286cca869ce037a4ec6c03d4ec0c2505", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-18 21:25:28", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-18 19:46:18", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-18 19:46:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 59170.0, "date": "2025-12-18", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "2788753e-b06c-42c8-aae5-1018a251b611", "_rev": "2-b6a1e47f607658d06ef9ad7ffbd04709", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-18 21:26:20", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-18 19:47:42", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-18 19:47:42", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 17060.0, "date": "2025-12-18", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "a42d56a0-5a34-491c-a5f6-32ce835efc81", "_rev": "2-bc8d7f018fcd0e1370f021a74b3b0c62", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-18 21:23:46", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-18 20:52:30", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-18 20:52:30", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "13c6da7b-8963-4aba-9c79-883a340f21e7", "rate": null, "quantity": 83935.0, "date": "2025-11-18", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "678ef40c-affa-4576-a7e2-f440d835f8a8", "_rev": "2-eefd975eeb318f72bc92c608f496ada9", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-18 21:26:04", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-18 20:54:33", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-18 20:54:33", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 372522.0, "date": "2025-12-18", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "3d422050-0933-46c9-ae47-636f7718d595", "_rev": "2-3273a569d68bf66b206746b74d99ca9a", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-25 20:43:00", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-25 20:39:59", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-25 20:39:59", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 61320.0, "date": "2025-12-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "b5f5fced-f33c-47aa-9ff0-e2168b848ede", "_rev": "2-bb589f51830a758c76cee2129db34d5b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-25 20:43:14", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-25 20:41:15", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-25 20:41:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 400222.0, "date": "2025-12-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "4a28d283-4b24-4dbb-b2b5-6baf38b5a876", "_rev": "2-d323356c40c8da29426b088c605d1e5d", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-25 20:43:27", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-25 20:41:58", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-25 20:41:58", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 19340.0, "date": "2025-12-25", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "814dd21d-a4f4-4daa-a2a5-660dbb8b60a2", "_rev": "2-3394e0d06ee46a2bb3b0bb003c5f14f5", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-02 09:28:55", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-29 11:17:16", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-29 11:17:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 2620200.0, "date": "2025-12-24", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "5aa94ea0-0cfb-40a3-b6cf-f1f3f5e2b21f", "_rev": "1-921d2c2635ff3592d36b899038f26115", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-29 14:43:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-29 14:43:48", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c8c6c5f8-f761-4e6e-baa1-636eba451873", "rate": null, "quantity": 6500.0, "date": "2025-12-29", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "165a693a-bd87-44a5-8e02-844ceb90103c", "_rev": "2-a38a7da976c83f14dffe018235248ffa", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-01 20:30:01", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-01 19:38:09", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-01-01 19:38:09", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 63550.0, "date": "2026-01-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "3a644e49-355f-42ea-8b8c-cad0c297e06c", "_rev": "2-bc1cd1ad7ee77fb3d23315383a492a41", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-01 20:30:23", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-01 19:40:10", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-01-01 19:40:10", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 424722.0, "date": "2026-01-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "8ce41b95-2f59-4c2b-bf49-c96d946465c9", "_rev": "2-3f28a1ca28f5d6cddd616b0cad1ccf81", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-01 20:30:47", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-01 19:41:33", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-01-01 19:41:33", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 21580.0, "date": "2026-01-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "41c2664e-1dc6-4e4a-9fe0-db670629da1f", "_rev": "2-8d31b4f957521a45e61081fc967445b9", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-08 09:50:55", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-01-02 09:29:37", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-01-02 09:29:37", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 2622600.0, "date": "2026-01-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "71dc36a5-8b1a-4f31-b5fb-8aacca06eb09", "_rev": "1-fd8b8f736fc0d3fe8f8c0e69e8978e87", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-01-08 09:49:29", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-01-08 09:49:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "78d7ab73-4e55-46fa-a208-1a21656cfa01", "rate": null, "quantity": 3.0, "date": "2025-12-31", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "043c1a41-722e-4c94-970b-cda1cd94e66d", "_rev": "2-762a2be265e3bacb7eb118e873fc51e7", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-08 20:04:45", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-08 20:01:13", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-08 20:04:45", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 449522.0, "date": "2026-01-08", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "5f76d8f1-a9da-4c21-a2c7-aa999a820cc5", "_rev": "2-c4608e53d04941e8f61f96a166f5829f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-08 20:04:15", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-08 20:02:02", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-08 20:04:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 65590.0, "date": "2026-01-08", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "71ee5ed6-96d3-4c3c-ae99-3d15bb788371", "_rev": "2-15a6720ed3b8f9d0016234b0f77ec64e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-08 20:04:56", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-08 20:02:37", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-08 20:04:56", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 23760.0, "date": "2026-01-08", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "efd872fc-518f-4f04-9776-222faa025eab", "_rev": "2-c67bfe0b3caf5642449ecd71df963783", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-15 20:02:29", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-15 19:59:01", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-15 20:02:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 67720.0, "date": "2026-01-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "806713c7-b52a-4491-bb43-338d7d3a9bbe", "_rev": "2-6d362db7f4e7738cb88e9064bfca54fd", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-15 20:02:41", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-15 19:59:59", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-15 20:02:41", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 474022.0, "date": "2026-01-15", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "267ff80a-b381-4905-b13f-e814ba56bb00", "_rev": "4-232b9693f1ba5324e227a101f3261318", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2026-01-15 20:02:52", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-15 20:00:55", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-15 20:02:52", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 25730.0, "date": "2026-01-15", "status": null, "change_count": 1, "remark": null, "is_complete": null}
|
||||
{"_id": "6ac3176d-75e7-4013-adda-1f1e52b5174f", "_rev": "2-403e2cf80f971d0838a6f415878ed98b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "approval_status": "pending_confirm", "approval_comment": "同意", "approval_time": "2026-01-22 20:52:03", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-22 20:38:31", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-22 20:52:03", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 69770.0, "date": "2026-01-22", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "adf3d301-abb7-45af-a2c3-078a91a983ce", "_rev": "2-616055bdf1e629de64591edb8ac596f1", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "approval_status": "pending_confirm", "approval_comment": "同意", "approval_time": "2026-01-22 20:52:22", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-22 20:39:52", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-22 20:52:22", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 500722.0, "date": "2026-01-22", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "2dc7327a-7b9c-4b13-b19b-d33e726f64c1", "_rev": "2-863a20ccfcc875b4fb27a3f7b608b334", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "approval_status": "pending_confirm", "approval_comment": "同意", "approval_time": "2026-01-22 20:52:35", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-22 20:51:14", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-22 20:52:35", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 27870.0, "date": "2026-01-22", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "1a9ae6a7-aa55-433b-8e1b-e1fe865ff8f1", "_rev": "2-d1c5e7bfc65e395cb57d651ce5deef6f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "approval_status": "pending_confirm", "approval_comment": "同意", "approval_time": "2026-01-29 21:53:45", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-29 21:30:06", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-29 21:53:45", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "cbb9c312-c8af-437a-a7a2-7f856c77f758", "rate": null, "quantity": 524122.0, "date": "2026-01-29", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "11b59bd0-48a8-4cf4-b058-271134addadc", "_rev": "2-7c34bbd321597b79cec0b92d71a0a784", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "approval_status": "pending_confirm", "approval_comment": "同意", "approval_time": "2026-01-29 21:53:18", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-29 21:31:19", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-29 21:53:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "62daee88-aa2e-4c80-aed7-234597b98873", "rate": null, "quantity": 71910.0, "date": "2026-01-29", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "2d59d674-94bc-4df7-82d4-6383b2ddb50f", "_rev": "2-59c6fe08cd166318377323146b621a9c", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "approval_status": "pending_confirm", "approval_comment": "同意", "approval_time": "2026-01-29 21:54:08", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2026-01-29 21:32:17", "updated_by": "30717a50-9bcc-4327-a1f0-5aa6f3a56f42", "updated_by_name": "杜光远", "updated_at": "2026-01-29 21:54:08", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "fd67540c-58c1-40a9-a051-410e908ac39c", "rate": null, "quantity": 29930.0, "date": "2026-01-29", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
{"_id": "bfe51026-3087-408d-ab4d-88f7122cebee", "_rev": "1-9da880454978941be3aa47ca1fd4aac0", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-02-06 10:24:46", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:24:46", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "construction_task_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7f349a96-2b5f-4b95-b307-f734ba66feb0", "rate": null, "quantity": 2630000.0, "date": "2026-02-01", "status": null, "change_count": 0, "remark": null, "is_complete": null}
|
||||
@@ -0,0 +1,65 @@
|
||||
{"_id": "0a5f071c-101c-45fc-92dc-f828500a00bb", "_rev": "2-fce52f36ed9a7a9a73d14ad814e96d45", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "低压厂用电配电系统采购合同", "short_name": "", "code": "DP", "contract_type": "product", "currency": "CNY", "manager_name": "李倩", "manager_phone": "15884389937", "sign_company": "乐山一拉得电网自动化有限公司", "company_id": "cd9e9224-a08f-4bed-81a6-b289b74506e8", "sign_date": "2024-08-05", "plan_end_date": "", "total_price": 1496.007, "sub_name": null}
|
||||
{"_id": "1974b17f-e35f-4053-bbc8-3c1cee0a65ce", "_rev": "1-5146505f8c3e63dde800661dace39b09", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "粉煤灰采购合同", "short_name": "", "code": "FM", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "19c887cb-a0c7-4dd9-9c37-63d53e049ab8", "_rev": "2-2db21aa199f320ad64924da1ff5cedfa", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "高压厂用变采购合同", "short_name": "", "code": "GB", "contract_type": "product", "currency": "CNY", "manager_name": "张大树", "manager_phone": "15202203612", "sign_company": "沈阳中变电气有限责任公司", "company_id": "0798431d-115a-4b1c-b95a-78470160fa9e", "sign_date": "2024-07-05", "plan_end_date": "", "total_price": 1039.0, "sub_name": null}
|
||||
{"_id": "22b8d43f-3ea2-412a-a5b0-5329b8998d6f", "_rev": "2-8671517a34257ad4ba531d072a802f03", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "发电机采购合同", "short_name": "", "code": "DJ", "contract_type": "product", "currency": "CNY", "manager_name": "孙浩翔", "manager_phone": "15183679645", "sign_company": "东方电气集团东方电机有限公司", "company_id": "ab5ab605-f27a-461b-9a88-73d1eafde5ed", "sign_date": "2021-12-20", "plan_end_date": "", "total_price": 55000.0, "sub_name": null}
|
||||
{"_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "_rev": "5-8d9ac0d36e38d6c804e5d6e97e134a15", "field_metadata": {"sign_company": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}, "manager_name": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}, "manager_phone": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}, "sign_date": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}, "total_price": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}, "company_id": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}, "sub_name": {"approval_status": "approved", "approval_flow_id": "bd6a894d-1500-47cc-91f5-8a043d969200"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "陈萌", "manager_phone": "13618131285", "sign_company": "中国葛洲坝集团三峡建设工程有限公司", "company_id": "1ff5b102-2f9e-496c-8591-1a8e32407c7f", "sign_date": "2019-11-21", "plan_end_date": "", "total_price": 300349.997815, "sub_name": "金沙江上游叶巴滩水电站引水发电系统工程"}
|
||||
{"_id": "37b54e2a-c159-4cca-a64a-13f379ff64aa", "_rev": "2-6ef682e033156dd6adce1f54221a30f5", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "1f7ebb95-5a0d-4181-91c3-fd60ac85eb24"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "1f7ebb95-5a0d-4181-91c3-fd60ac85eb24"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "1f7ebb95-5a0d-4181-91c3-fd60ac85eb24"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "1f7ebb95-5a0d-4181-91c3-fd60ac85eb24"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "1f7ebb95-5a0d-4181-91c3-fd60ac85eb24"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "水泥采购合同", "short_name": "", "code": "SN", "contract_type": "product", "currency": "CNY", "manager_name": "曾强", "manager_phone": "15729742054", "sign_company": "四川蜀府贸易有限公司", "company_id": "3ab47229-6da8-4efb-aa44-b96866a2ce13", "sign_date": "2019-11-01", "plan_end_date": "", "total_price": 0.0, "sub_name": null}
|
||||
{"_id": "58c1f591-ba44-4452-b8db-4f9e7a9ea9f2", "_rev": "2-fa12aca0acea25778ea456e37319e242", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "3ad5a49f-3f46-43f0-8e1b-da3e8ef6d4f7"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "3ad5a49f-3f46-43f0-8e1b-da3e8ef6d4f7"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "3ad5a49f-3f46-43f0-8e1b-da3e8ef6d4f7"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "3ad5a49f-3f46-43f0-8e1b-da3e8ef6d4f7"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "3ad5a49f-3f46-43f0-8e1b-da3e8ef6d4f7"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "3ad5a49f-3f46-43f0-8e1b-da3e8ef6d4f7"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "励磁系统采购合同", "short_name": "", "code": "LC", "contract_type": "product", "currency": "CNY", "manager_name": "林小燕", "manager_phone": "18620810988", "sign_company": "广州擎天实业有限公司", "company_id": "357c7eaf-5a33-4999-be94-79c42bfbd955", "sign_date": "2023-11-05", "plan_end_date": "", "total_price": 997.0, "sub_name": null}
|
||||
{"_id": "5b7984d7-c947-424f-9694-8f17d45b86b4", "_rev": "1-3e04204a80ed4666a88e6093019cce3f", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "钢筋采购合同", "short_name": "", "code": "GJ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "640fc215-134a-49b5-a486-225fa6a0c5c5", "_rev": "2-1944151104959bfae9e8bb5eeb167104", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "卷扬式启闭机采购合同", "short_name": "", "code": "JQ", "contract_type": "product", "currency": "CNY", "manager_name": "盘锡军", "manager_phone": "13508136201", "sign_company": "中国水利水电夹江水工机械有限公司", "company_id": "77316fb4-6167-432b-94e5-89c3d8a6b900", "sign_date": "2023-06-10", "plan_end_date": "", "total_price": 5879.62647, "sub_name": null}
|
||||
{"_id": "66fb4f4b-872b-420e-9d01-f392a840b5a1", "_rev": "2-d6eeeb51cf7b9ca0c101ca71613f5cfc", "field_metadata": {"sub_name": {}, "sign_company": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:31:53", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "液压式启闭机采购合同", "short_name": "", "code": "YQ", "contract_type": "product", "currency": "CNY", "manager_name": "邵和凤", "manager_phone": "86-0519-68869977", "sign_company": "常州液压成套设备厂有限公司", "company_id": "48a5f1a7-5d5e-41cf-8676-042f1d5316f1", "sign_date": "2023-05-17", "plan_end_date": "", "total_price": 4320.668, "sub_name": null}
|
||||
{"_id": "8dde2df6-ae27-4e61-ad80-62dbb7c93ec1", "_rev": "2-cf72684e0adca75b0964a2867fa40c2b", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "主变压器采购合同", "short_name": "", "code": "ZB", "contract_type": "product", "currency": "CNY", "manager_name": "刘朝伟", "manager_phone": "18049180542", "sign_company": "西安西电变压器有限责任公司", "company_id": "e0ceec90-0ad7-417f-a669-fd4f5db07eff", "sign_date": "2023-05-01", "plan_end_date": "", "total_price": 10636.0, "sub_name": null}
|
||||
{"_id": "a28a8672-c913-4113-90c9-0371f6db9342", "_rev": "2-d1f1754306c2f305773a10ef15fe8877", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "桥式起重设备采购合同", "short_name": "", "code": "QJ", "contract_type": "product", "currency": "CNY", "manager_name": "顾成", "manager_phone": "15988838408", "sign_company": "杭州华新机电工程有限公司", "company_id": "67fa779d-2ce9-468f-b94f-a3d29f1f22c9", "sign_date": "2022-03-06", "plan_end_date": "", "total_price": 2538.5, "sub_name": null}
|
||||
{"_id": "a2d49172-e04a-4cca-b801-fc7b0d6d0fac", "_rev": "1-e67eab72d8518bf2eb9ef6d136fac391", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "计算机监控系统采购合同", "short_name": "", "code": "JK", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "b8822b9e-4511-497f-98cc-b45be77b1e96", "_rev": "3-422d73286c0b8763967afbd5b1fa8732", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-12-25 08:58:00", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "高压厂用电配电系统采购合同", "short_name": "", "code": "GP", "contract_type": "product", "currency": "CNY", "manager_name": "范有春", "manager_phone": "13584015343", "sign_company": "国电南京自动化股份有限公司", "company_id": "97be34dc-0a17-4ce5-baea-0f3ceee61103", "sign_date": "2024-08-05", "plan_end_date": "", "total_price": 1183.532, "sub_name": null}
|
||||
{"_id": "bf665bb5-0d84-43ea-80ce-a8b575d75d62", "_rev": "2-1a96bdff129ff87285b5645543045baf", "field_metadata": {"sub_name": {}, "sign_company": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:35:54", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "发电机出口断路器采购合同", "short_name": "", "code": "JD", "contract_type": "product", "currency": "CNY", "manager_name": "王昆", "manager_phone": "0898-3637", "sign_company": "某公司海南物资有限公司", "company_id": "930dfaf9-708e-4ec0-95f4-521b10bf1c00", "sign_date": "2024-10-14", "plan_end_date": "", "total_price": 3101.4078, "sub_name": null}
|
||||
{"_id": "cab2e475-6420-43f1-ac0b-f1d60032714d", "_rev": "4-f67e3117d7702c42262346c11399300b", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "水轮机采购合同", "short_name": "", "code": "SJ", "contract_type": "product", "currency": "CNY", "manager_name": "张佩伦", "manager_phone": "13845042361", "sign_company": "哈尔滨电机厂有限责任公司", "company_id": "2e465bd8-b240-4046-bf00-187d22823f7b", "sign_date": "2021-12-20", "plan_end_date": "", "total_price": 49868.0, "sub_name": null}
|
||||
{"_id": "f28cd32a-564b-4a7c-926f-7d138f6c2439", "_rev": "4-04ac0fe825703c925d64cf576b50b3fd", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "GIS系统采购合同", "short_name": "", "code": "GS", "contract_type": "product", "currency": "CNY", "manager_name": "蒋本涛", "manager_phone": "16620702201", "sign_company": "特变电工中发上海高压开关有限公司", "company_id": "34db820f-860c-4c6e-9326-5c7cb385bf50", "sign_date": "2023-12-09", "plan_end_date": "", "total_price": 5854.5, "sub_name": null}
|
||||
{"_id": "f509a975-7c1f-4fbb-bbda-2f85eaed1b3d", "_rev": "1-9e77cd4df35dfac9e7396027bf617cdb", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "调速器及其附属设备采购合同", "short_name": "", "code": "TS", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "f95333ee-5f6f-421c-94ce-7edc063b8c62", "_rev": "2-6bcfbcb07db37652267cbe94c4dbaaf3", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "外加剂采购合同", "short_name": "", "code": "YJ", "contract_type": "product", "currency": "CNY", "manager_name": "钟本建", "manager_phone": "18378711407", "sign_company": "江苏苏博特新材料股份有限公司", "company_id": "2ca09c22-68b4-4e43-b9fa-619dcda5f325", "sign_date": "2025-09-18", "plan_end_date": "", "total_price": 3122.05725, "sub_name": null}
|
||||
{"_id": "01d834e5-a68e-4828-a484-141abd70f05b", "_rev": "1-a25fe62211e83da87a6add15dc3964f9", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "预可及可研阶段设计合同", "short_name": "", "code": "KY", "contract_type": "service", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "031687f4-e525-4ac4-95f5-5d1343dbad26", "_rev": "1-06819e3979392975096aff4a1fbba6ea", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "计算机监控系统采购合同", "short_name": "", "code": "JK", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "039c3d1b-9bbe-40d9-baae-5db156785101", "_rev": "1-c486e288853e5da7b348ccc6635e8023", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "主变压器采购合同", "short_name": "", "code": "ZB", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "07d0c522-598c-4a19-a35d-b18bbd152ce1", "_rev": "1-c78dace9399528967f535928a885e6b9", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "粉煤灰采购合同", "short_name": "", "code": "FM", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "1351be9d-3ca3-48f1-be29-fb39b2c3ff15", "_rev": "1-045893b99fe3893ae31279cd337c26a8", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "施工总承包合同", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "2cd96d17-4068-43a9-b856-07c2e071e8cc", "_rev": "1-3eb7dbb439a7bb07c9a9ff7cca1ddd48", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "卷扬式启闭机采购合同", "short_name": "", "code": "JQ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "6425478f-d383-4466-a387-d9c927a7c8d9", "_rev": "1-d89f2d4adcdb74473ea663847d39258a", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "高压厂用电配电系统采购合同", "short_name": "", "code": "GP", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "74c610c4-4268-4143-a1b4-d1e30f450997", "_rev": "1-c44a58393786db4c938bcb75778b8a59", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "水轮机采购合同", "short_name": "", "code": "SJ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "829d3033-6bb1-42eb-88d3-fc1f01985751", "_rev": "1-7542d6ae004ec4569f076a6193d0a55a", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "高压厂用变采购合同", "short_name": "", "code": "GB", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "864c50af-64d8-4278-a1fc-a30804a91d3c", "_rev": "1-0e83f058b3ede95c4ec5b725ca19a6e3", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "外加剂采购合同", "short_name": "", "code": "YJ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "86c5bd6f-7737-4aca-b3af-330ab3c9208b", "_rev": "1-6ade569cfae4e2aebcb052cbb611f8ba", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "发电机出口断路器采购合同", "short_name": "", "code": "JD", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "89bf5647-594a-441f-9ea5-e9105f50dd78", "_rev": "1-b9d3fb8795c8a82f8d32a9d8f40bc69d", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "调速器及其附属设备采购合同", "short_name": "", "code": "TS", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "8b3bd771-1b7f-42f6-adb6-4bae6c765a3f", "_rev": "1-c968fbda1a32122d4e58bf8956652ca1", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "水泥采购合同", "short_name": "", "code": "SN", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "8ca9f6af-d93a-4274-9651-3325ea1a47a2", "_rev": "1-0581194684233e4f0514d8f82c6b500b", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "液压式启闭机采购合同", "short_name": "", "code": "YQ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "8cb77da2-1460-42b0-9ca4-7aa5afa58b99", "_rev": "1-3ed037a217dbaddd7ed772fc2b633f82", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "钢筋采购合同", "short_name": "", "code": "GJ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "92e3de18-354c-4acf-9cb5-58ee55708fbd", "_rev": "1-b4b8fcf8f642923ee4dff56c79185a12", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "低压厂用电配电系统采购合同", "short_name": "", "code": "DP", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "97de1925-849d-4470-8d4d-673790a1b0d4", "_rev": "2-5e93b129a73ffd8da40594b465736325", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "e7374b6f-1da0-4898-b1ca-3780b1ccd583"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "e7374b6f-1da0-4898-b1ca-3780b1ccd583"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "e7374b6f-1da0-4898-b1ca-3780b1ccd583"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "e7374b6f-1da0-4898-b1ca-3780b1ccd583"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "e7374b6f-1da0-4898-b1ca-3780b1ccd583"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "e7374b6f-1da0-4898-b1ca-3780b1ccd583"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "PC合同", "short_name": "", "code": "PC", "contract_type": "service", "currency": "CNY", "manager_name": "周正荣", "manager_phone": "13688518858", "sign_company": "中国水利水电第九工程局有限公司", "company_id": "1098875c-e949-47b1-9f40-237eb507f890", "sign_date": "2024-04-27", "plan_end_date": "", "total_price": 19189.1128}
|
||||
{"_id": "9e112f2d-60c3-4429-9861-e6348d0d6fd4", "_rev": "1-d5002e648133aeb7d4e980013858279f", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "发电机采购合同", "short_name": "", "code": "DJ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "b16ab690-a318-4927-a165-0f2b92759922", "_rev": "1-7b3a12fe3e6566ef03f17f4fe91b6e9c", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "EPC合同", "short_name": "", "code": "EPC", "contract_type": "service", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "b4c2ffab-2c38-49cd-a065-31b9a4b22d1b", "_rev": "1-da62e0ba44360b61d8fdce5e59da9d47", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "闸门及拦污栅采购合同", "short_name": "", "code": "ZM", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "bf9ee1f3-eb6f-495c-a2db-6c95ecf3f8d8", "_rev": "1-78af5c009d812a38851811e8cbf89b44", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "桥式起重设备采购合同", "short_name": "", "code": "QJ", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "d12b617e-d7c5-4211-822b-5fd3f46bc0f9", "_rev": "1-7125ff63bf662b16112494d5da8f8c69", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "平行发包施工合同", "short_name": "", "code": "PF", "contract_type": "service", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "d13a7aec-9cd8-4cf6-ac21-ccd1b79bcc55", "_rev": "1-6e45e0ceab068bb3d0200068a48b6fec", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "励磁系统采购合同", "short_name": "", "code": "LC", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "d3a3c0a1-11c3-40a0-9a62-90ede90d9d03", "_rev": "1-72492ad0ad20d994915ce9000e22c2c1", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "招标及施工图阶段勘察设计合同", "short_name": "", "code": "E", "contract_type": "service", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "e00871cb-6404-4909-b0ce-db0baecae803", "_rev": "1-47f981270f690493da2a35eac33feb7b", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "GIS系统采购合同", "short_name": "", "code": "GS", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "e312644b-2e3e-4179-8de0-0183e2c72cf4", "_rev": "1-4ed002f311a39b822eced667e9e6b54e", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "低压厂用变采购合同", "short_name": "", "code": "DB", "contract_type": "product", "currency": "CNY", "manager_name": "", "manager_phone": "", "sign_company": "", "company_id": "", "sign_date": "", "plan_end_date": "", "total_price": 0.0}
|
||||
{"_id": "eba6d9e0-fad4-456d-a325-38f5bd064b33", "_rev": "3-232f2c450e1c7c6cd78fbbe3c98db741", "field_metadata": {"sign_company": {"approval_status": "approved", "approval_flow_id": "a396f802-5c4a-4f9b-939b-57823a3de707"}, "manager_name": {"approval_status": "approved", "approval_flow_id": "a396f802-5c4a-4f9b-939b-57823a3de707"}, "manager_phone": {"approval_status": "approved", "approval_flow_id": "a396f802-5c4a-4f9b-939b-57823a3de707"}, "sign_date": {"approval_status": "approved", "approval_flow_id": "a396f802-5c4a-4f9b-939b-57823a3de707"}, "total_price": {"approval_status": "approved", "approval_flow_id": "a396f802-5c4a-4f9b-939b-57823a3de707"}, "company_id": {"approval_status": "approved", "approval_flow_id": "a396f802-5c4a-4f9b-939b-57823a3de707"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "其他种类施工合同", "short_name": "", "code": "OSC", "contract_type": "service", "currency": "CNY", "manager_name": "翟万全", "manager_phone": "13778606062", "sign_company": "中国水利水电第六工程局有限公司", "company_id": "e88c8c18-bc49-4bab-acc5-6fb78f4c7f8f", "sign_date": "2024-04-25", "plan_end_date": "", "total_price": 237461.901806}
|
||||
{"_id": "f3b9c510-568f-4bed-98a4-a602142e1957", "_rev": "2-34a461291110e89ab8eda93dba69705b", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "5e846885-fca8-4034-9de2-904500f907eb"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "5e846885-fca8-4034-9de2-904500f907eb"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "5e846885-fca8-4034-9de2-904500f907eb"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "5e846885-fca8-4034-9de2-904500f907eb"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "5e846885-fca8-4034-9de2-904500f907eb"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "5e846885-fca8-4034-9de2-904500f907eb"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "监理合同", "short_name": "", "code": "JL", "contract_type": "service", "currency": "CNY", "manager_name": "李卫国", "manager_phone": "13408531717", "sign_company": "四川二滩国际工程咨询有限责任公司", "company_id": "4b069ce4-3687-4263-a1f2-4735c22c3f8e", "sign_date": "2023-09-10", "plan_end_date": "", "total_price": 9886.622299}
|
||||
{"_id": "3bb70c3c-f2e0-4763-a38e-35ef2937794e", "_rev": "5-81cf334903232c9ff1521ea0aa340ceb", "field_metadata": {"sign_company": {"approval_status": "approved", "approval_flow_id": "62a58344-b905-44c5-a864-df6f654642cc"}, "manager_name": {"approval_status": "approved", "approval_flow_id": "62a58344-b905-44c5-a864-df6f654642cc"}, "manager_phone": {"approval_status": "approved", "approval_flow_id": "62a58344-b905-44c5-a864-df6f654642cc"}, "sign_date": {"approval_status": "approved", "approval_flow_id": "62a58344-b905-44c5-a864-df6f654642cc"}, "total_price": {"approval_status": "approved", "approval_flow_id": "62a58344-b905-44c5-a864-df6f654642cc"}, "company_id": {"approval_status": "approved", "approval_flow_id": "62a58344-b905-44c5-a864-df6f654642cc"}, "sub_name": {}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 10:48:03", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 10:48:03", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "PC合同", "short_name": "", "code": "PC", "contract_type": "service", "currency": "CNY", "manager_name": "杨泽恒", "manager_phone": "13769162007", "sign_company": "中国水利水电第十四工程局有限公司", "company_id": "6db1ed5b-f52a-4142-867c-d8b2731ead71", "sign_date": "2024-08-10", "plan_end_date": "", "total_price": 130146.226803, "sub_name": null}
|
||||
{"_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "_rev": "3-7af855893060fd0beb401ba70e00dd28", "field_metadata": {"sign_company": {"approval_status": "approved", "approval_flow_id": "54a26de7-17e4-4731-bb5f-9ace208a8f5e"}, "manager_name": {"approval_status": "approved", "approval_flow_id": "54a26de7-17e4-4731-bb5f-9ace208a8f5e"}, "manager_phone": {"approval_status": "approved", "approval_flow_id": "54a26de7-17e4-4731-bb5f-9ace208a8f5e"}, "sign_date": {"approval_status": "approved", "approval_flow_id": "54a26de7-17e4-4731-bb5f-9ace208a8f5e"}, "total_price": {"approval_status": "approved", "approval_flow_id": "54a26de7-17e4-4731-bb5f-9ace208a8f5e"}, "company_id": {"approval_status": "approved", "approval_flow_id": "54a26de7-17e4-4731-bb5f-9ace208a8f5e"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 11:07:12", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 11:07:12", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "PC合同", "short_name": "", "code": "PC", "contract_type": "service", "currency": "CNY", "manager_name": "何周蓉", "manager_phone": "18821761836", "sign_company": "中国水利水电第五工程局有限公司", "company_id": "538e01cd-85cb-42b3-b313-16977f7a5224", "sign_date": "2024-08-09", "plan_end_date": "", "total_price": 140301.0959}
|
||||
{"_id": "c7c2d101-32a5-4d69-bfd6-4bb0ac210271", "_rev": "2-ca63c4d0e485200408e0759b20218e69", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:04:44", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:04:44", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "PC合同", "short_name": "", "code": "PC", "contract_type": "service", "currency": "CNY", "manager_name": "范开平", "manager_phone": "18284596507", "sign_company": "中国水利水电第十工程局有限公司", "company_id": "31b6b6d7-989b-4abe-a7e1-6d518f3a4020", "sign_date": "2024-02-06", "plan_end_date": "", "total_price": 7357.365783}
|
||||
{"_id": "1efec366-1ca7-478a-8ecf-f5e457c44b05", "_rev": "2-26e7f31e29415ed1212a93a1fed5c2f9", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "af3da397-3d04-4fe3-ab8d-89af12385ebf"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "af3da397-3d04-4fe3-ab8d-89af12385ebf"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "af3da397-3d04-4fe3-ab8d-89af12385ebf"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "af3da397-3d04-4fe3-ab8d-89af12385ebf"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "af3da397-3d04-4fe3-ab8d-89af12385ebf"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "af3da397-3d04-4fe3-ab8d-89af12385ebf"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:22:24", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:22:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "监理合同", "short_name": "", "code": "JL", "contract_type": "service", "currency": "CNY", "manager_name": "李卫国", "manager_phone": "13408531717", "sign_company": "四川二滩国际工程咨询有限责任公司", "company_id": "4b069ce4-3687-4263-a1f2-4735c22c3f8e", "sign_date": "2023-09-10", "plan_end_date": "", "total_price": 9886.622299}
|
||||
{"_id": "cfda7940-05f2-44b4-8d54-d465fcc32dd6", "_rev": "2-1baae09efb2a9e7403ff358be15a1c15", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "45771f66-8eff-4928-a360-c5805feae3fd"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "45771f66-8eff-4928-a360-c5805feae3fd"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "45771f66-8eff-4928-a360-c5805feae3fd"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "45771f66-8eff-4928-a360-c5805feae3fd"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "45771f66-8eff-4928-a360-c5805feae3fd"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "45771f66-8eff-4928-a360-c5805feae3fd"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:33:49", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:33:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "监理合同", "short_name": "", "code": "JL", "contract_type": "service", "currency": "CNY", "manager_name": "许朝政", "manager_phone": "18080015170", "sign_company": "中国电建集团贵阳勘测设计研究院有限公司", "company_id": "98892419-6a71-4d7e-a0ac-ad5a0a15f1d6", "sign_date": "2023-11-29", "plan_end_date": "", "total_price": 31900.0}
|
||||
{"_id": "cfb16f0a-313f-440f-a7b1-d045f29ab77c", "_rev": "2-b9d4de773f2e7b337110a19b61934189", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "49bb3689-9f98-489b-b17f-74b0f918fac2"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "49bb3689-9f98-489b-b17f-74b0f918fac2"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "49bb3689-9f98-489b-b17f-74b0f918fac2"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "49bb3689-9f98-489b-b17f-74b0f918fac2"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "49bb3689-9f98-489b-b17f-74b0f918fac2"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "49bb3689-9f98-489b-b17f-74b0f918fac2"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-10 15:46:30", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-10 15:46:30", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "name": "PC合同", "short_name": "", "code": "PC", "contract_type": "service", "currency": "CNY", "manager_name": "翟万全", "manager_phone": "13778606062", "sign_company": "中国水利水电第六工程局有限公司", "company_id": "e88c8c18-bc49-4bab-acc5-6fb78f4c7f8f", "sign_date": "2024-04-25", "plan_end_date": "", "total_price": 237461.901806}
|
||||
{"_id": "54ffaa56-529e-43ae-a8bc-28ab4f71b9e4", "_rev": "2-5c66f20d823ffa0fcd9681b1528fe929", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "e50c01c7-3e95-4f98-a994-5cf7a8ad47ce"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-12 21:38:17", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-12 21:38:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "刘鑫升", "manager_phone": "18783671696", "sign_company": "中国水利水电第五工程局有限公司", "company_id": "538e01cd-85cb-42b3-b313-16977f7a5224", "sign_date": "2017-02-10", "plan_end_date": "", "total_price": 87089.7711, "sub_name": "金沙江上游叶巴滩水电站导流洞及场内右岸高线公路工程"}
|
||||
{"_id": "4ab0bb83-64f7-4b64-96d6-907c843b7639", "_rev": "2-c3b62b400f3e78dbc7fb023b91a580ab", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "034ad739-a27f-48ac-9c0a-505a88c5c557"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-12 21:39:40", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-12 21:39:40", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "李万洲", "manager_phone": "13330310033", "sign_company": "中国水利水电第七工程局有限公司", "company_id": "4be9e1da-9ebf-4a2a-b6bd-14a41ac31858", "sign_date": "2018-09-25", "plan_end_date": "", "total_price": 468226.0168, "sub_name": "金沙江上游叶巴滩水电站大坝工程施工合同"}
|
||||
{"_id": "8db97a3a-be48-4ad9-957a-a67034eb99ed", "_rev": "2-26ca014f29814f4642b28a4dbf5bed48", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "acb765f9-f06b-4349-b7a8-6423cacd95fe"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:45:16", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:45:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "刘明洋", "manager_phone": "13673561123", "sign_company": "中国水利水电第九工程局有限公司", "company_id": "1098875c-e949-47b1-9f40-237eb507f890", "sign_date": "2022-11-06", "plan_end_date": "", "total_price": 5860.0714, "sub_name": "金沙江上游叶巴滩水电站过鱼系统土建工程"}
|
||||
{"_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "_rev": "2-2eae2725b60978f0a1f5468014b7e360", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "427fc623-5626-4a73-a2f5-8d6229e105f3"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:27:49", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:27:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "张加银", "manager_phone": "18228575199", "sign_company": "中国水利水电第七工程局有限公司", "company_id": "4be9e1da-9ebf-4a2a-b6bd-14a41ac31858", "sign_date": "2022-10-04", "plan_end_date": "", "total_price": 16695.0, "sub_name": "金沙江上游叶巴滩水电站机电设备安装工程施工"}
|
||||
{"_id": "3cdc3f40-7e4a-4601-b643-7ad3037c7ec3", "_rev": "2-82f602763e8dd9f87b70ea457321e9fc", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "cc441f0f-efea-44cc-b96d-0dbfadd7c98c"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:37:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:37:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "周召", "manager_phone": "15729368737", "sign_company": "中国水利水电第四工程局有限公司", "company_id": "9c80aace-ba73-4550-8fef-3080b51027d9", "sign_date": "2016-06-28", "plan_end_date": "", "total_price": 55446.65, "sub_name": "金沙江上游叶巴滩水电站场内左岸高线公路及俄德西沟沟水处理工程"}
|
||||
{"_id": "9a2a4e3f-e748-4229-89bc-ad72eba4b352", "_rev": "2-abca3fb4effbced2a372a42a207f4488", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "f7d58861-b272-46db-b06b-f3c52a30d839"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:58:32", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:58:32", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "贾真", "manager_phone": "18215559382", "sign_company": "中国葛洲坝集团三峡建设工程有限公司", "company_id": "1ff5b102-2f9e-496c-8591-1a8e32407c7f", "sign_date": "2015-10-30", "plan_end_date": "", "total_price": 9963.65, "sub_name": "进场交通工程合同"}
|
||||
{"_id": "2e7feb46-667b-4b40-be23-f4f5589f0492", "_rev": "2-23bc2a69f10bfba4a6248310672d930f", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "e08025a8-2d78-4736-8ce0-9d2f4cad5817"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:02:13", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:02:13", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "贾真", "manager_phone": "18215559382", "sign_company": "中国葛洲坝集团三峡建设工程有限公司", "company_id": "1ff5b102-2f9e-496c-8591-1a8e32407c7f", "sign_date": "2015-11-09", "plan_end_date": "", "total_price": 33972.19, "sub_name": "金沙江上游叶巴滩水电站场内低线公路工程合同文件"}
|
||||
{"_id": "ac565d4c-3911-4690-953e-d4ceb5a56442", "_rev": "2-872137190f012da5f1e987b23c51b3d6", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "5d991769-6b70-4b14-a5e9-4061eaa3aab3"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:16:17", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:16:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "岩孟", "manager_phone": "14787938856", "sign_company": "云南水电十四局东华建筑工程有限公司", "company_id": "594a09af-8944-476d-b098-7aebe96ad4e8", "sign_date": "2025-05-15", "plan_end_date": "", "total_price": 8108.48, "sub_name": "金沙江上游叶巴滩水电站枢纽区装修工程"}
|
||||
{"_id": "dc90ce00-f4bf-401f-a64a-4ac0df9ebca3", "_rev": "2-ee209303e0dfaf6b2e5ecda0ec30b3b6", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "394637f6-ad74-48fc-a875-197a9b452759"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:20:26", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:20:26", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "施工总承包合同(不含设计、采购)", "short_name": "", "code": "CG", "contract_type": "service", "currency": "CNY", "manager_name": "彭清海", "manager_phone": "18981727633", "sign_company": "中国安能集团第三工程局有限公司", "company_id": "1115a7f3-b2c1-4bfb-8c89-605250c402dd", "sign_date": "2022-08-16", "plan_end_date": "", "total_price": 6393.57, "sub_name": "叶巴滩水电站1#承包商营地复建工程"}
|
||||
{"_id": "0e055981-96e8-4eaa-9a5d-61190023be0b", "_rev": "2-b419b48919de210d6257cb5d7a65f242", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "45c58e7c-e56a-460e-abff-c7441d9d7938"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:26:30", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:26:30", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "监理合同", "short_name": "", "code": "JL", "contract_type": "service", "currency": "CNY", "manager_name": "徐凤奎", "manager_phone": "18985191672", "sign_company": "中国电建集团贵阳勘测设计研究院有限公司", "company_id": "98892419-6a71-4d7e-a0ac-ad5a0a15f1d6", "sign_date": "2016-06-21", "plan_end_date": "", "total_price": 3545.98, "sub_name": "金沙江上游叶巴滩电站前期准备工程建设监理服务"}
|
||||
{"_id": "199920c8-dced-492b-958c-b5b58be3915b", "_rev": "4-b2db7944391fc2389f1fcc43428dd541", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "sub_name": {}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:17:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:17:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "招标及施工图阶段勘察设计合同", "short_name": "", "code": "E", "contract_type": "service", "currency": "CNY", "manager_name": "蒙富强", "manager_phone": "13547829339", "sign_company": "中国电建集团成都勘测设计研究院有限公司", "company_id": "936c6316-8d87-4681-a3b5-b90ed4804a06", "sign_date": "2024-06-11", "plan_end_date": "", "total_price": 123700.0, "sub_name": null}
|
||||
{"_id": "2c1a1c28-9e8d-4280-bb7d-81a24fd62735", "_rev": "4-bc845a79ab12cb1e6d1dfdef09d50d80", "field_metadata": {"sign_company": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "manager_name": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "manager_phone": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "sign_date": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "total_price": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "company_id": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "sub_name": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:41:46", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:41:46", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "name": "监理合同", "short_name": "", "code": "JL", "contract_type": "service", "currency": "CNY", "manager_name": "赵兴旺", "manager_phone": "18891990251", "sign_company": "中国水利水电建设工程咨询西北有限公司", "company_id": "b4656ed6-5329-4673-93c8-d11e15d6ece5", "sign_date": "2018-03-30", "plan_end_date": "", "total_price": 13625.93, "sub_name": "金沙江上游叶巴滩水电站主体工程施工监理服务合同"}
|
||||
@@ -0,0 +1 @@
|
||||
{"_id": "35df6c1d-b6c6-4605-8417-76f04256b62d", "_rev": "1-2ec86151cbf7e59e27e7e4644c2e645b", "field_metadata": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:52:06", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:52:06", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_change", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "title": "合同变更、设计变更、索赔补偿", "reason": "合同变更、设计变更、索赔补偿", "before_amount": 300349.997815, "after_amount": 377340.0, "change_time": "2025-11-14", "attachment_ids": ["8e72f2aa198341bf98e1441087f5246d"]}
|
||||
@@ -0,0 +1,65 @@
|
||||
{"_id": "108211ba-dccd-4f03-a243-a04905c11539", "_rev": "1-1cfb0acffec77a2328f2cf5afa6fd88e", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "f509a975-7c1f-4fbb-bbda-2f85eaed1b3d", "contract_type": null, "show_name": "调速器及其附属设备采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "13c83c67-a726-4e1c-ade5-bb146a3dac4f", "_rev": "5-38b3a147cf6c27041162e891684c8ef3", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "bc76ea78-95d2-4552-b8dd-8e0084a6cdeb", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "9292bb5b-6387-4563-a902-6af96c76fadf"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "bc76ea78-95d2-4552-b8dd-8e0084a6cdeb"}}, "approval_user": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "approval_status": "under_review", "approval_comment": "集团管理员驳回", "approval_time": "2026-02-06 10:35:54", "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:40:13", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "bf665bb5-0d84-43ea-80ce-a8b575d75d62", "contract_type": null, "show_name": "发电机出口断路器采购合同", "complete_price": 2791.26702, "actual_complete_date": null, "actual_start_date": "2025-04-26", "plan_complete_date": "2026-06-30", "plan_start_date": "2024-10-14", "plan_node": [{"date": "2024-10-14", "quantity": 0.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 3101.4078, "is_audit": false}], "status": 1, "contract_price": 3101.4078, "sort": 0, "delay_days": 0, "statistic_date": "2025-04-26"}
|
||||
{"_id": "2e321d92-0a10-4a02-9bce-63cd81b669c1", "_rev": "4-eade0c6bcf6317ab8d7cbbb478f5cb65", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "61037dea-2719-4285-962d-d2746e214b40", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "efad5757-7e45-49d2-a43b-c774ef4ddd07"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "61037dea-2719-4285-962d-d2746e214b40"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "8dde2df6-ae27-4e61-ad80-62dbb7c93ec1", "contract_type": null, "show_name": "主变压器采购合同", "complete_price": 5845.4, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-12-31", "plan_start_date": "2023-05-01", "plan_node": [{"date": "2023-05-01", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 10636.0, "is_audit": false}], "status": 1, "contract_price": 10636.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "3a60f300-aeae-4fef-81b9-ed55f24ace90", "_rev": "1-a26ae8e9daec0b0198d8bce032d0e522", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "5b7984d7-c947-424f-9694-8f17d45b86b4", "contract_type": null, "show_name": "钢筋采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "4b2ad982-3eec-440c-837e-c2f24661a7da", "_rev": "1-88338860d64c4ac4a3fcae7fb22a8304", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "a2d49172-e04a-4cca-b801-fc7b0d6d0fac", "contract_type": null, "show_name": "计算机监控系统采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "5bd1e03e-5ab3-46f7-9ba5-12f91f500ffd", "_rev": "4-77904298e6119c3e265622489257958b", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "fab43465-ee0e-409c-a486-59e45c8de398", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "f392f91b-9e3a-4586-9a4d-bd0226d680a5"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "fab43465-ee0e-409c-a486-59e45c8de398"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "22b8d43f-3ea2-412a-a5b0-5329b8998d6f", "contract_type": null, "show_name": "发电机采购合同", "complete_price": 33670.07, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-12-31", "plan_start_date": "2021-12-20", "plan_node": [{"date": "2021-12-20", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 55000.0, "is_audit": false}], "status": 1, "contract_price": 55000.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "5c8acfd1-9b0a-4a7a-a8f6-d54d56069d31", "_rev": "5-08116ab309d32d3eddb15cfa8e8d54a2", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "fbeb4fb0-6069-404c-8b36-69e8a80afba2", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "1a8ce1b1-7d8c-4846-98c0-d05583931cb0"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "fbeb4fb0-6069-404c-8b36-69e8a80afba2"}}, "approval_user": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "approval_status": "under_review", "approval_comment": "集团管理员驳回", "approval_time": "2026-02-06 10:31:53", "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:41:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "66fb4f4b-872b-420e-9d01-f392a840b5a1", "contract_type": null, "show_name": "液压式启闭机采购合同", "complete_price": 2948.05175, "actual_complete_date": null, "actual_start_date": "2025-10-18", "plan_complete_date": "2026-12-31", "plan_start_date": "2023-05-17", "plan_node": [{"date": "2023-05-17", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 4320.668, "is_audit": false}], "status": 1, "contract_price": 4320.668, "sort": 0, "delay_days": 0, "statistic_date": "2025-10-18"}
|
||||
{"_id": "7203cef0-6ac6-4686-8730-a9db0c64f4ca", "_rev": "2-081f0565630022fc23d7c634f72c189d", "field_metadata": {"plan_node": {"edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "1f7ebb95-5a0d-4181-91c3-fd60ac85eb24"}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "37b54e2a-c159-4cca-a64a-13f379ff64aa", "contract_type": null, "show_name": "水泥采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": "2019-11-01", "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "7c23f528-2266-4b85-9f3b-283a64027e0f", "_rev": "1-45261a548a975a1dcae857b77846bc51", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "1974b17f-e35f-4053-bbc8-3c1cee0a65ce", "contract_type": null, "show_name": "粉煤灰采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "7cfd7cbe-d737-41e4-ad0d-647ce267bbb4", "_rev": "8-47837c02ab84c9fb59384ecf5044a07c", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "713c3654-5cc2-4a47-942f-8e2ff2d5f278", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "713c3654-5cc2-4a47-942f-8e2ff2d5f278"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "713c3654-5cc2-4a47-942f-8e2ff2d5f278"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "713c3654-5cc2-4a47-942f-8e2ff2d5f278"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3121d85a-87b8-4ae1-a6c4-1ad1a78562ea", "contract_type": null, "show_name": "施工总承包合同", "complete_price": 303538.29, "actual_complete_date": "2025-12-09", "actual_start_date": "2025-10-21", "plan_complete_date": "2026-12-31", "plan_start_date": "2019-11-21", "plan_node": [{"date": "2019-11-21", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 300349.997815, "is_audit": false}], "status": 1, "contract_price": 300349.997815, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "7ed0fed1-4018-4086-b7e0-4a7f139ac8dc", "_rev": "29-a707760c5ca590f507461edf7c05a8a0", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "e485cd12-9594-430d-ba72-a56fecf813d1", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "e485cd12-9594-430d-ba72-a56fecf813d1"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "e485cd12-9594-430d-ba72-a56fecf813d1"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "e485cd12-9594-430d-ba72-a56fecf813d1"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "58c1f591-ba44-4452-b8db-4f9e7a9ea9f2", "contract_type": null, "show_name": "励磁系统采购合同", "complete_price": 579.3, "actual_complete_date": null, "actual_start_date": "2023-12-07", "plan_complete_date": "2027-12-31", "plan_start_date": "2023-11-05", "plan_node": [{"date": "2023-11-05", "quantity": 0.0, "is_audit": false}, {"date": "2023-12-01", "quantity": 99.7, "is_audit": false}, {"date": "2024-05-31", "quantity": 299.1, "is_audit": false}, {"date": "2025-05-31", "quantity": 403.2, "is_audit": false}, {"date": "2025-07-31", "quantity": 543.3, "is_audit": false}, {"date": "2026-02-28", "quantity": 797.6, "is_audit": false}, {"date": "2027-12-31", "quantity": 997.0, "is_audit": false}], "status": 1, "contract_price": 997.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "aff42f0d-4beb-4ed7-a519-1d9a5247d403", "_rev": "4-ec83622c56cb96e6b5fc61d439133427", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "c5de8769-f5f8-4aa7-8a59-c2bf63ff6d9c", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "6cf5373c-59ed-4625-a1cc-66557fc0513e"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "c5de8769-f5f8-4aa7-8a59-c2bf63ff6d9c"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "19c887cb-a0c7-4dd9-9c37-63d53e049ab8", "contract_type": null, "show_name": "高压厂用变采购合同", "complete_price": 831.2, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-06-30", "plan_start_date": "2024-07-05", "plan_node": [{"date": "2024-07-05", "quantity": 0.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 1039.0, "is_audit": false}], "status": 1, "contract_price": 1039.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "b1b1ac3a-33f5-4a1d-a1bd-191258a904c6", "_rev": "4-ec3c9ee90378243be1a5a8c81a064c8c", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "56a415ae-b49a-4fd8-af80-602593d20d8e", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "a0bc3d5e-0648-47d1-95ea-07eb3d70267e"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "56a415ae-b49a-4fd8-af80-602593d20d8e"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "a28a8672-c913-4113-90c9-0371f6db9342", "contract_type": null, "show_name": "桥式起重设备采购合同", "complete_price": 2079.64, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-06-30", "plan_start_date": "2022-03-06", "plan_node": [{"date": "2022-03-06", "quantity": 0.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 2538.5, "is_audit": false}], "status": 1, "contract_price": 2538.5, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "b298b89e-abcf-4a76-a85f-ff83f5da8342", "_rev": "2-2698ad8e210648e114f7ac057d8e7efb", "field_metadata": {"plan_node": {"edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "c86403cc-4f8e-41e0-9811-fd2d40984e83"}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "f95333ee-5f6f-421c-94ce-7edc063b8c62", "contract_type": null, "show_name": "外加剂采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": "2025-09-18", "plan_node": [], "status": null, "contract_price": 3122.05725, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "b311422b-fa21-4fa3-84e0-7fd47b636bbf", "_rev": "4-0a1c044e51693960cba9c2413bea0769", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "b88d4048-4922-41ae-a0b7-5e5b679bc9c7", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "aa35f6d4-503b-4b5e-8c33-3d04cb75b2e9"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "b88d4048-4922-41ae-a0b7-5e5b679bc9c7"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "640fc215-134a-49b5-a486-225fa6a0c5c5", "contract_type": null, "show_name": "卷扬式启闭机采购合同", "complete_price": 3863.62, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-12-31", "plan_start_date": "2023-06-10", "plan_node": [{"date": "2023-06-10", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 5879.62647, "is_audit": false}], "status": 1, "contract_price": 5879.62647, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "c3831212-8134-4d5f-8ac8-c6c41fbbf6db", "_rev": "4-63fee2d5de2044f517942de3ec78a741", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "9fe6c1d6-c3b6-44ef-a017-44d6e0064451", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "cddeaab8-42d8-4f66-93b5-1f3c9a5cd161"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "9fe6c1d6-c3b6-44ef-a017-44d6e0064451"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "b8822b9e-4511-497f-98cc-b45be77b1e96", "contract_type": null, "show_name": "高压厂用电配电系统采购合同", "complete_price": 946.83, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-06-30", "plan_start_date": "2024-08-05", "plan_node": [{"date": "2024-08-05", "quantity": 0.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 1183.532, "is_audit": false}], "status": 1, "contract_price": 1183.532, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "ca573e09-e78e-4ae7-ae4f-347844f471a7", "_rev": "65-1128e39fb68dce620d3b20028be30ec1", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "946a2991-e1e9-4d1e-b046-91981b65d8de", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "35329b8f-88d0-46a6-8e9a-70842eb87dff"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "946a2991-e1e9-4d1e-b046-91981b65d8de"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:02:10", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "f28cd32a-564b-4a7c-926f-7d138f6c2439", "contract_type": null, "show_name": "GIS系统采购合同", "complete_price": 4669.61, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2025-12-31", "plan_start_date": "2023-12-09", "plan_node": [{"date": "2023-12-09", "quantity": 0.0, "is_audit": false}, {"date": "2025-12-31", "quantity": 5854.5, "is_audit": false}], "status": -1, "contract_price": 5854.5, "sort": 0, "delay_days": 58, "statistic_date": "2025-12-09"}
|
||||
{"_id": "d41b13cf-49c3-49ba-9613-e6dda9635c4e", "_rev": "4-e51cd96682c242386e88591e62395e27", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "2e6048ef-c39d-4715-b97a-8cbe55c5e8a9", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "9869e136-01a5-4672-8312-84a5e1e63c6c"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "2e6048ef-c39d-4715-b97a-8cbe55c5e8a9"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "0a5f071c-101c-45fc-92dc-f828500a00bb", "contract_type": null, "show_name": "低压厂用电配电系统采购合同", "complete_price": 1196.81, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-06-30", "plan_start_date": "2024-08-05", "plan_node": [{"date": "2024-08-05", "quantity": 0.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 1496.007, "is_audit": false}], "status": 1, "contract_price": 1496.007, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "e2f88f30-b118-4319-b214-553ebbe1c3ae", "_rev": "7-f04d2f15eea761b608a91c21bf989396", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "05a3ef22-30de-49c0-b995-c102922c887e", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "8da3e66b-566b-4f6c-b4e9-fd28e3faf977"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "05a3ef22-30de-49c0-b995-c102922c887e"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "cab2e475-6420-43f1-ac0b-f1d60032714d", "contract_type": null, "show_name": "水轮机采购合同", "complete_price": 34859.02, "actual_complete_date": null, "actual_start_date": "2025-12-09", "plan_complete_date": "2026-12-31", "plan_start_date": "2021-12-20", "plan_node": [{"date": "2021-12-20", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 49868.0, "is_audit": false}], "status": 1, "contract_price": 49868.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "02bcc9a6-bb66-4fa2-a426-80b8d388cf03", "_rev": "1-5d8e936db480b714746358bad3c94e71", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "8cb77da2-1460-42b0-9ca4-7aa5afa58b99", "contract_type": null, "show_name": "钢筋采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "06ba04bc-dd06-4acb-9b8d-8c67b8a9c66c", "_rev": "1-59540a11fe3d9e0b18cce96aff314cd0", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3a3c0a1-11c3-40a0-9a62-90ede90d9d03", "contract_type": null, "show_name": "招标及施工图阶段勘察设计合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "15997d63-3888-4877-a34f-c8cff32fe454", "_rev": "1-c3d20f7961ec46de3b38a23b07bb5c16", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "86c5bd6f-7737-4aca-b3af-330ab3c9208b", "contract_type": null, "show_name": "发电机出口断路器采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "1b0b8090-f344-40da-b6df-8609e56d2a2e", "_rev": "1-94151c11c783471e2656124c70866e41", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "6425478f-d383-4466-a387-d9c927a7c8d9", "contract_type": null, "show_name": "高压厂用电配电系统采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "26157d07-d02b-40aa-8afe-47204b4bc3e3", "_rev": "1-56566c7734e0deac6209ba90cd0b3eb7", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "92e3de18-354c-4acf-9cb5-58ee55708fbd", "contract_type": null, "show_name": "低压厂用电配电系统采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "30962d2a-7526-4c09-9597-271a7ad4a9fa", "_rev": "1-c9763fdbd7c18e90ff8992b4593c14a5", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "89bf5647-594a-441f-9ea5-e9105f50dd78", "contract_type": null, "show_name": "调速器及其附属设备采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "36328f07-72b8-44db-aeb6-466fd1acf2e4", "_rev": "1-471f37907d364bda3734c52611368ec9", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "8ca9f6af-d93a-4274-9651-3325ea1a47a2", "contract_type": null, "show_name": "液压式启闭机采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "3a381622-0547-40e9-a543-03a2bc46fbdc", "_rev": "1-dfa170648b77b7b61f3910cf069d1ccd", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "864c50af-64d8-4278-a1fc-a30804a91d3c", "contract_type": null, "show_name": "外加剂采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "42a4b974-dee6-405b-941b-e705e8876dc6", "_rev": "1-cda3edacc9fa0da8359328a0ad179730", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "bf9ee1f3-eb6f-495c-a2db-6c95ecf3f8d8", "contract_type": null, "show_name": "桥式起重设备采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "5329e272-544d-4a36-9106-7a7c71487d30", "_rev": "1-b8d0f719b8761ddae1779229d83a0bda", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "2cd96d17-4068-43a9-b856-07c2e071e8cc", "contract_type": null, "show_name": "卷扬式启闭机采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "544430cd-1301-43e0-8f7e-a471d9438983", "_rev": "7-7cfa86cd7c74ba4e18edd11764d41bec", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "30ca7a79-2de4-4dce-b5bf-989d1c69bb0b", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "30ca7a79-2de4-4dce-b5bf-989d1c69bb0b"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "30ca7a79-2de4-4dce-b5bf-989d1c69bb0b"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "30ca7a79-2de4-4dce-b5bf-989d1c69bb0b"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "97de1925-849d-4470-8d4d-673790a1b0d4", "contract_type": null, "show_name": "PC合同", "complete_price": 9564.931481, "actual_complete_date": null, "actual_start_date": "2025-10-10", "plan_complete_date": "2032-02-29", "plan_start_date": "2024-04-27", "plan_node": [{"date": "2024-04-27", "quantity": 0.0, "is_audit": false}, {"date": "2032-02-29", "quantity": 13740.9171, "is_audit": false}], "status": 1, "contract_price": 13740.9171, "sort": 0, "delay_days": 0, "statistic_date": "2025-10-10"}
|
||||
{"_id": "55a2c813-b35e-41a3-83db-d7b65256ac7e", "_rev": "1-0be3c5ca773e6658db21a4bb431404c6", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d13a7aec-9cd8-4cf6-ac21-ccd1b79bcc55", "contract_type": null, "show_name": "励磁系统采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "579f1102-e1dc-4e26-b00e-4ea499d7a66b", "_rev": "1-e306838d4c7a7f52b8c86daf6f1ee8db", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "b4c2ffab-2c38-49cd-a065-31b9a4b22d1b", "contract_type": null, "show_name": "闸门及拦污栅采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "66c8a4c8-94ec-417e-bf7e-c72d0b9ec9fb", "_rev": "1-f4fe77f9f34206fc4fce323f95cb5938", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "9e112f2d-60c3-4429-9861-e6348d0d6fd4", "contract_type": null, "show_name": "发电机采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "80108bb4-3abb-4861-886b-9b949dcb09aa", "_rev": "1-e5da88819ef5283beb1b940dc0487d0a", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "8b3bd771-1b7f-42f6-adb6-4bae6c765a3f", "contract_type": null, "show_name": "水泥采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "9301adc7-9af1-4621-a7e3-842048a1508c", "_rev": "1-86d50203afe40312b4ee7393c61714ad", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "829d3033-6bb1-42eb-88d3-fc1f01985751", "contract_type": null, "show_name": "高压厂用变采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "93ecc764-4167-459a-ad14-c169723d724e", "_rev": "1-e300f09cc961c643509c4c8157d4f8d6", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "e00871cb-6404-4909-b0ce-db0baecae803", "contract_type": null, "show_name": "GIS系统采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "9ca3b188-c661-4e28-8f60-7e5923e5ea3d", "_rev": "1-e6a3afb379b44566048737eb25485442", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "1351be9d-3ca3-48f1-be29-fb39b2c3ff15", "contract_type": null, "show_name": "施工总承包合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "bb914a70-aa39-45f1-8dd4-809d2af6945d", "_rev": "1-1ee8b1e6639b8e45db7257b9329d272b", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "031687f4-e525-4ac4-95f5-5d1343dbad26", "contract_type": null, "show_name": "计算机监控系统采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "c0a41de9-a40d-4b1d-a014-552f70fc7e6f", "_rev": "1-bac3879a991b787abf70d7967431ba84", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "b16ab690-a318-4927-a165-0f2b92759922", "contract_type": null, "show_name": "EPC合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "c4ded355-fb10-46e8-b829-442bf42c16f1", "_rev": "5-14aa25675e6c9d9686ae0a134e6d48cd", "field_metadata": {"plan_node": {"approval_status": "rejected", "approval_flow_id": "26f8888e-ee51-4060-9fa4-c47d8a9ff8b9", "edit_after_approve": true}, "contract_price": {"approval_status": "rejected", "approval_flow_id": "26f8888e-ee51-4060-9fa4-c47d8a9ff8b9"}, "plan_start_date": {"approval_status": "rejected", "approval_flow_id": "26f8888e-ee51-4060-9fa4-c47d8a9ff8b9"}, "plan_complete_date": {"approval_status": "rejected", "approval_flow_id": "26f8888e-ee51-4060-9fa4-c47d8a9ff8b9"}}, "approval_user": null, "approval_status": "rejected", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "eba6d9e0-fad4-456d-a325-38f5bd064b33", "contract_type": null, "show_name": "其他种类施工合同", "complete_price": 14576.616806, "actual_complete_date": null, "actual_start_date": "2025-10-18", "plan_complete_date": "2031-09-30", "plan_start_date": "2024-04-25", "plan_node": [{"date": "2024-04-25", "quantity": 0.0, "is_audit": false}, {"date": "2031-09-30", "quantity": 237461.901806, "is_audit": false}], "status": 1, "contract_price": 237461.901806, "sort": 0, "delay_days": 0, "statistic_date": "2025-10-18"}
|
||||
{"_id": "c63915bd-8ac9-441d-8b0a-2e9ba73468ac", "_rev": "1-d20fc90a6714741c662acfa957d88636", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "74c610c4-4268-4143-a1b4-d1e30f450997", "contract_type": null, "show_name": "水轮机采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "cf6693ae-9b5e-4309-9353-b0903c06b3e3", "_rev": "1-0859361d95f2be2d3b67030bc9b7d56a", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "07d0c522-598c-4a19-a35d-b18bbd152ce1", "contract_type": null, "show_name": "粉煤灰采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "d603eea4-9338-49b3-8214-188f5043df42", "_rev": "116-fb7f938f48c4a94578a58a98ae48a3f4", "field_metadata": {"plan_node": {"approval_status": "rejected", "approval_flow_id": "24346a35-39bd-4199-b7f0-1d4896edaa56", "edit_after_approve": true}, "contract_price": {"approval_status": "rejected", "approval_flow_id": "24346a35-39bd-4199-b7f0-1d4896edaa56"}, "plan_start_date": {"approval_status": "rejected", "approval_flow_id": "24346a35-39bd-4199-b7f0-1d4896edaa56"}, "plan_complete_date": {"approval_status": "rejected", "approval_flow_id": "24346a35-39bd-4199-b7f0-1d4896edaa56"}}, "approval_user": null, "approval_status": "rejected", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:02:08", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "f3b9c510-568f-4bed-98a4-a602142e1957", "contract_type": null, "show_name": "监理合同", "complete_price": 494.331115, "actual_complete_date": null, "actual_start_date": "2023-12-19", "plan_complete_date": "2024-01-10", "plan_start_date": "2023-09-10", "plan_node": [{"date": "2023-09-10", "quantity": 0.0, "is_audit": false}, {"date": "2024-01-10", "quantity": 9886.622299, "is_audit": false}], "status": -1, "contract_price": 9886.622299, "sort": 0, "delay_days": 779, "statistic_date": "2023-12-19"}
|
||||
{"_id": "d86077c8-364b-4405-8605-389c193ad405", "_rev": "1-cb78fa8ec27dbdfceb3b30eff4b330ea", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "01d834e5-a68e-4828-a484-141abd70f05b", "contract_type": null, "show_name": "预可及可研阶段设计合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "dc15e38e-da1a-4fc8-87db-637559a23b5d", "_rev": "1-c62142bd7fe72d25da84d3a54dbf5e62", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "e312644b-2e3e-4179-8de0-0183e2c72cf4", "contract_type": null, "show_name": "低压厂用变采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "f18a109b-f265-47f0-bedc-ed3b9f344056", "_rev": "1-60ddce46cc7b8efdc6f86844c6232b90", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "039c3d1b-9bbe-40d9-baae-5db156785101", "contract_type": null, "show_name": "主变压器采购合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "fc95705f-348e-4954-8789-03c81d1e22bb", "_rev": "1-3a92c5581edea898a410db91c588dc7c", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d12b617e-d7c5-4211-822b-5fd3f46bc0f9", "contract_type": null, "show_name": "平行发包施工合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": null, "plan_node": [], "status": null, "contract_price": 0.0, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "5bd7f162-5dbd-4063-b46f-312cc139a8e2", "_rev": "6-93bed497aa55c757e27a5a2a6ec32357", "field_metadata": {"plan_node": {"approval_status": "rejected", "approval_flow_id": "bc12180f-4da3-42b6-a5c1-bd1ed3c38d06", "edit_after_approve": true}, "contract_price": {"approval_status": "rejected", "approval_flow_id": "bc12180f-4da3-42b6-a5c1-bd1ed3c38d06"}, "plan_start_date": {"approval_status": "rejected", "approval_flow_id": "bc12180f-4da3-42b6-a5c1-bd1ed3c38d06"}, "plan_complete_date": {"approval_status": "rejected", "approval_flow_id": "bc12180f-4da3-42b6-a5c1-bd1ed3c38d06"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 10:48:03", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 10:48:03", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "3bb70c3c-f2e0-4763-a38e-35ef2937794e", "contract_type": null, "show_name": "PC合同", "complete_price": 12801.295844, "actual_complete_date": null, "actual_start_date": "2025-10-10", "plan_complete_date": "2033-11-30", "plan_start_date": "2024-08-10", "plan_node": [{"date": "2024-08-10", "quantity": 0.0, "is_audit": false}, {"date": "2033-11-30", "quantity": 130146.226803, "is_audit": false}], "status": 1, "contract_price": 130146.226803, "sort": 0, "delay_days": 0, "statistic_date": "2025-10-10"}
|
||||
{"_id": "8c7416d4-1813-47a7-9808-769c1d9cb0c0", "_rev": "4-9f1e007ce4d5e331b8a33d6359b943f0", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "4c520bea-714d-4b69-a18a-2ed821ac08ef", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "4c520bea-714d-4b69-a18a-2ed821ac08ef"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "4c520bea-714d-4b69-a18a-2ed821ac08ef"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "4c520bea-714d-4b69-a18a-2ed821ac08ef"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 11:07:12", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 11:07:12", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d3b7e26e-ef1c-4d5b-812d-ce88d0c41f9b", "contract_type": null, "show_name": "PC合同", "complete_price": 16505.52665, "actual_complete_date": null, "actual_start_date": "2025-11-06", "plan_complete_date": "2033-11-30", "plan_start_date": "2024-08-09", "plan_node": [{"date": "2024-08-09", "quantity": 0.0, "is_audit": false}, {"date": "2033-11-30", "quantity": 140301.0959, "is_audit": false}], "status": 1, "contract_price": 140301.0959, "sort": 0, "delay_days": 0, "statistic_date": "2025-11-06"}
|
||||
{"_id": "9d990fe5-17b1-4658-9b3d-6355992ecb9b", "_rev": "2-28f284a6a3efeca26b2a71a53fd0f102", "field_metadata": {"plan_node": {"edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "6043018d-6375-4b58-a739-ec80b04a9cdf"}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:04:44", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:04:44", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "c7c2d101-32a5-4d69-bfd6-4bb0ac210271", "contract_type": null, "show_name": "PC合同", "complete_price": 0.0, "actual_complete_date": null, "actual_start_date": null, "plan_complete_date": null, "plan_start_date": "2024-02-06", "plan_node": [], "status": null, "contract_price": 7357.365783, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "00e06088-d376-4a73-b4d0-cc0de5736004", "_rev": "4-2f1cf85eb95bfe47ab47bbd86e868975", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "abccdd6f-a65f-4e19-9f09-d19153763b42", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "abccdd6f-a65f-4e19-9f09-d19153763b42"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "abccdd6f-a65f-4e19-9f09-d19153763b42"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "abccdd6f-a65f-4e19-9f09-d19153763b42"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:22:24", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:22:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "1efec366-1ca7-478a-8ecf-f5e457c44b05", "contract_type": null, "show_name": "监理合同", "complete_price": 2483.056686, "actual_complete_date": null, "actual_start_date": "2025-11-06", "plan_complete_date": "2032-03-31", "plan_start_date": "2023-09-10", "plan_node": [{"date": "2023-09-10", "quantity": 0.0, "is_audit": false}, {"date": "2032-03-31", "quantity": 9886.622299, "is_audit": false}], "status": 1, "contract_price": 9886.622299, "sort": 0, "delay_days": 0, "statistic_date": "2025-11-06"}
|
||||
{"_id": "6c68c4f9-ab72-4e0f-bff9-31e9db967316", "_rev": "4-95983cfa4d14483368f1a2546c9e5ea9", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "3fe8c2cb-9f28-4973-9bbc-8c8a6354fa27", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "3fe8c2cb-9f28-4973-9bbc-8c8a6354fa27"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "3fe8c2cb-9f28-4973-9bbc-8c8a6354fa27"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "3fe8c2cb-9f28-4973-9bbc-8c8a6354fa27"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:33:49", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:33:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "cfda7940-05f2-44b4-8d54-d465fcc32dd6", "contract_type": null, "show_name": "监理合同", "complete_price": 7970.0, "actual_complete_date": null, "actual_start_date": "2025-08-19", "plan_complete_date": "2032-12-31", "plan_start_date": "2023-11-29", "plan_node": [{"date": "2023-11-29", "quantity": 0.0, "is_audit": false}, {"date": "2032-12-31", "quantity": 31900.0, "is_audit": false}], "status": 1, "contract_price": 31900.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-08-19"}
|
||||
{"_id": "bcd6d13c-e529-4f2d-ab7b-481458c587e2", "_rev": "4-3e21fb7e455f3ca339032bc2c5830bd7", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "e39c6db9-0e7f-4cbb-8c10-727fb5f4b763", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "e39c6db9-0e7f-4cbb-8c10-727fb5f4b763"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "e39c6db9-0e7f-4cbb-8c10-727fb5f4b763"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "e39c6db9-0e7f-4cbb-8c10-727fb5f4b763"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-10 15:46:30", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-10 15:46:30", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "cfb16f0a-313f-440f-a7b1-d045f29ab77c", "contract_type": null, "show_name": "PC合同", "complete_price": 14576.616806, "actual_complete_date": null, "actual_start_date": "2025-10-18", "plan_complete_date": "2031-09-30", "plan_start_date": "2024-04-25", "plan_node": [{"date": "2024-04-25", "quantity": 0.0, "is_audit": false}, {"date": "2031-09-30", "quantity": 237461.901806, "is_audit": false}], "status": 1, "contract_price": 237461.901806, "sort": 0, "delay_days": 0, "statistic_date": "2025-10-18"}
|
||||
{"_id": "e3adcce0-db55-4361-846c-3a52c99e8dd9", "_rev": "4-a90e6d20a33ca225fc796d7693cc36a9", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "48dbee8e-de31-4fe3-a11a-f6a9855afadc", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "48dbee8e-de31-4fe3-a11a-f6a9855afadc"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "48dbee8e-de31-4fe3-a11a-f6a9855afadc"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "48dbee8e-de31-4fe3-a11a-f6a9855afadc"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-12 21:38:17", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-12 21:38:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "54ffaa56-529e-43ae-a8bc-28ab4f71b9e4", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 92588.19, "actual_complete_date": "2024-12-13", "actual_start_date": "2024-12-13", "plan_complete_date": "2026-12-31", "plan_start_date": "2017-02-10", "plan_node": [{"date": "2017-02-10", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 87089.7711, "is_audit": false}], "status": 1, "contract_price": 87089.7711, "sort": 0, "delay_days": 0, "statistic_date": "2024-12-13"}
|
||||
{"_id": "cb4ea5f6-e8e3-4a50-a5c0-829c02be3ff6", "_rev": "5-1753b4be4114da9e0b9824cd4a47221b", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "cdc604dc-6d34-4bbf-b929-8ca880a5c562", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "cdc604dc-6d34-4bbf-b929-8ca880a5c562"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "cdc604dc-6d34-4bbf-b929-8ca880a5c562"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "cdc604dc-6d34-4bbf-b929-8ca880a5c562"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-12 21:39:40", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-12 21:39:40", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "4ab0bb83-64f7-4b64-96d6-907c843b7639", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 414461.27, "actual_complete_date": null, "actual_start_date": "2025-10-21", "plan_complete_date": "2027-12-31", "plan_start_date": "2018-09-25", "plan_node": [{"date": "2018-09-25", "quantity": 0.0, "is_audit": false}, {"date": "2027-12-31", "quantity": 468226.0168, "is_audit": false}], "status": 1, "contract_price": 468226.0168, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "5789ef30-258b-4b2f-b8e9-1c644f3957fd", "_rev": "5-8c7f8098d3f834d8f7c66d795b54182e", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "7ad0406c-5ad1-4966-a5f5-8b207fbf4df3", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "7ad0406c-5ad1-4966-a5f5-8b207fbf4df3"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "7ad0406c-5ad1-4966-a5f5-8b207fbf4df3"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "7ad0406c-5ad1-4966-a5f5-8b207fbf4df3"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 10:45:16", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 10:45:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "8db97a3a-be48-4ad9-957a-a67034eb99ed", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 7282.39, "actual_complete_date": "2025-12-09", "actual_start_date": "2025-10-21", "plan_complete_date": "2027-06-30", "plan_start_date": "2022-11-06", "plan_node": [{"date": "2022-11-06", "quantity": 0.0, "is_audit": false}, {"date": "2027-06-30", "quantity": 5860.0714, "is_audit": false}], "status": 1, "contract_price": 5860.0714, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "ed4c9b00-efbb-41cc-8e67-13d3b0a80fd5", "_rev": "5-4870c34107b3899209e11a9b49095b11", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "5354668f-78c5-4389-8f16-a4b174f4d692", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "5354668f-78c5-4389-8f16-a4b174f4d692"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "5354668f-78c5-4389-8f16-a4b174f4d692"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "5354668f-78c5-4389-8f16-a4b174f4d692"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:27:49", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:27:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "773de8ab-8e21-4ad1-a420-d3709795baa0", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 9522.65, "actual_complete_date": null, "actual_start_date": "2025-11-14", "plan_complete_date": "2027-12-30", "plan_start_date": "2022-10-04", "plan_node": [{"date": "2022-10-04", "quantity": 0.0, "is_audit": false}, {"date": "2027-12-30", "quantity": 16695.0, "is_audit": false}], "status": 1, "contract_price": 16695.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "888377d9-545f-4573-a42d-7b93656e920c", "_rev": "5-ff4da36ceeb799a91b6690b50c0db017", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "d86d549f-475b-4265-8422-3a824de730d1", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "d86d549f-475b-4265-8422-3a824de730d1"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "d86d549f-475b-4265-8422-3a824de730d1"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "d86d549f-475b-4265-8422-3a824de730d1"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:37:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:37:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "3cdc3f40-7e4a-4601-b643-7ad3037c7ec3", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 57966.73, "actual_complete_date": "2025-12-09", "actual_start_date": "2025-01-10", "plan_complete_date": "2026-12-31", "plan_start_date": "2016-06-28", "plan_node": [{"date": "2016-06-28", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 55446.65, "is_audit": false}], "status": 1, "contract_price": 55446.65, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "c47d31fa-7195-42c7-8fc6-e1be2a2df876", "_rev": "5-0088b5868b38912b21feea5774071a3c", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "bd5895ac-1e0a-4daa-9929-fb5ced8cd67f", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "bd5895ac-1e0a-4daa-9929-fb5ced8cd67f"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "bd5895ac-1e0a-4daa-9929-fb5ced8cd67f"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "bd5895ac-1e0a-4daa-9929-fb5ced8cd67f"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:58:32", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:58:32", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "9a2a4e3f-e748-4229-89bc-ad72eba4b352", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 9194.43, "actual_complete_date": null, "actual_start_date": "2022-01-20", "plan_complete_date": "2026-12-31", "plan_start_date": "2015-10-30", "plan_node": [{"date": "2015-10-30", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 9963.65, "is_audit": false}], "status": 1, "contract_price": 9963.65, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "60f8d37c-efd4-464b-8d01-acdded4b6324", "_rev": "5-150eb11d7284e04dce1958f8532d7ced", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "7b40e453-e442-4f04-8692-7604e2b3f07e", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "7b40e453-e442-4f04-8692-7604e2b3f07e"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "7b40e453-e442-4f04-8692-7604e2b3f07e"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "7b40e453-e442-4f04-8692-7604e2b3f07e"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:02:13", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:02:13", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "2e7feb46-667b-4b40-be23-f4f5589f0492", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 30256.02, "actual_complete_date": null, "actual_start_date": "2024-12-18", "plan_complete_date": "2026-12-31", "plan_start_date": "2015-11-09", "plan_node": [{"date": "2015-11-09", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 33972.19, "is_audit": false}], "status": 1, "contract_price": 33972.19, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "ad5e5bc4-3a75-43f4-afc9-918e4624b1fb", "_rev": "5-cbfdb8b44e38eccff78a0ad98b852b61", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "2a76a3ca-8749-4d2e-91b6-35d96b797609", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "2a76a3ca-8749-4d2e-91b6-35d96b797609"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "2a76a3ca-8749-4d2e-91b6-35d96b797609"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "2a76a3ca-8749-4d2e-91b6-35d96b797609"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:16:17", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:16:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "ac565d4c-3911-4690-953e-d4ceb5a56442", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 1782.73, "actual_complete_date": null, "actual_start_date": "2025-10-21", "plan_complete_date": "2027-12-31", "plan_start_date": "2025-05-15", "plan_node": [{"date": "2025-05-15", "quantity": 0.0, "is_audit": false}, {"date": "2027-12-31", "quantity": 8108.48, "is_audit": false}], "status": 1, "contract_price": 8108.48, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "7a002e5c-6f3e-46a3-9924-12011f30eb97", "_rev": "5-b9c78921db1dc6e08adead0726064e08", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "7320049a-b5a2-430a-acff-5e47f6531525", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "7320049a-b5a2-430a-acff-5e47f6531525"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "7320049a-b5a2-430a-acff-5e47f6531525"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "7320049a-b5a2-430a-acff-5e47f6531525"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:20:26", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:20:26", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "dc90ce00-f4bf-401f-a64a-4ac0df9ebca3", "contract_type": null, "show_name": "施工总承包合同(不含设计、采购)", "complete_price": 5531.78, "actual_complete_date": null, "actual_start_date": "2025-01-10", "plan_complete_date": "2026-12-31", "plan_start_date": "2022-08-16", "plan_node": [{"date": "2022-08-16", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 6393.57, "is_audit": false}], "status": 1, "contract_price": 6393.57, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-09"}
|
||||
{"_id": "602471ee-e4af-40c3-a5c6-d82117b9853a", "_rev": "4-b4f9ddb0f9188ca344ccf8a35f97c910", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "22c750ca-f8e0-404f-904c-f73aabc34c78", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "22c750ca-f8e0-404f-904c-f73aabc34c78"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "22c750ca-f8e0-404f-904c-f73aabc34c78"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "22c750ca-f8e0-404f-904c-f73aabc34c78"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:26:30", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:26:30", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "0e055981-96e8-4eaa-9a5d-61190023be0b", "contract_type": null, "show_name": "监理合同", "complete_price": 3563.04, "actual_complete_date": "2024-06-12", "actual_start_date": "2024-06-12", "plan_complete_date": "2026-12-31", "plan_start_date": "2016-06-21", "plan_node": [{"date": "2016-06-21", "quantity": 0.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 3545.98, "is_audit": false}], "status": 1, "contract_price": 3545.98, "sort": 0, "delay_days": 0, "statistic_date": "2024-06-12"}
|
||||
{"_id": "b5669ab4-d583-449d-8ec9-a6752b99dbbe", "_rev": "11-e46a0520553d195ed5e053b4fb46dae0", "field_metadata": {"plan_node": {"approval_status": "rejected", "approval_flow_id": "52a077db-c3f9-442a-aba0-d0db1ac6becf", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "be53ad68-0232-4148-bae5-a725362ecd0e"}, "plan_complete_date": {"approval_status": "rejected", "approval_flow_id": "52a077db-c3f9-442a-aba0-d0db1ac6becf"}}, "approval_user": null, "approval_status": "rejected", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:17:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:17:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "199920c8-dced-492b-958c-b5b58be3915b", "contract_type": null, "show_name": "招标及施工图阶段勘察设计合同", "complete_price": 15979.15, "actual_complete_date": null, "actual_start_date": "2024-08-13", "plan_complete_date": "2028-12-31", "plan_start_date": "2024-06-11", "plan_node": [{"date": "2024-06-11", "quantity": 0.0, "is_audit": false}, {"date": "2028-12-31", "quantity": 123351.01, "is_audit": false}], "status": 1, "contract_price": 123700.0, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-12"}
|
||||
{"_id": "5a8fd1df-4fb4-478e-adbb-621fc1194d47", "_rev": "8-b5c37680357fac646145390af6c595b7", "field_metadata": {"plan_node": {"approval_status": "rejected", "approval_flow_id": "d279a09a-49e6-4fbe-94ef-8563ee478960", "edit_after_approve": true}, "contract_price": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "053194e3-732d-431d-8e87-9ba0e9389c24"}, "plan_complete_date": {"approval_status": "rejected", "approval_flow_id": "d279a09a-49e6-4fbe-94ef-8563ee478960"}}, "approval_user": null, "approval_status": "rejected", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:41:46", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:41:46", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "2c1a1c28-9e8d-4280-bb7d-81a24fd62735", "contract_type": null, "show_name": "监理合同", "complete_price": 13493.9985, "actual_complete_date": null, "actual_start_date": "2025-12-29", "plan_complete_date": "2027-06-30", "plan_start_date": "2018-03-30", "plan_node": [{"date": "2018-03-30", "quantity": 0.0, "is_audit": false}, {"date": "2027-06-30", "quantity": 13625.93, "is_audit": false}], "status": 1, "contract_price": 13625.93, "sort": 0, "delay_days": null, "statistic_date": "2025-12-29"}
|
||||
@@ -0,0 +1,44 @@
|
||||
{"_id": "70adde25-515c-432a-b729-5421a2a0cbed", "_rev": "4-91a53821a79cbc8c0e31dd8f281cfcb3", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "registered", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 09:55:19", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 09:55:19", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "d603eea4-9338-49b3-8214-188f5043df42", "date": "2023-12-19", "quantity": 494.331115, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 1}
|
||||
{"_id": "4cfebe7a-b9d6-4393-9c8f-68a152def8e6", "_rev": "1-8ffbfa7774c266083877401a6989e468", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 10:26:11", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 10:26:11", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "c4ded355-fb10-46e8-b829-442bf42c16f1", "date": "2025-10-18", "quantity": 14576.616806, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "de07aedd-98c9-4c23-bf4d-09b7c2a6482b", "_rev": "1-6d765fb3bf66fed856681ede56a6abef", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 10:58:14", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 10:58:14", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "5bd7f162-5dbd-4063-b46f-312cc139a8e2", "date": "2025-10-10", "quantity": 12801.295844, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "c8f11e62-5e9f-4300-b13c-e9272964e343", "_rev": "1-0288508ef97985dd340f8dd24f615fb1", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 11:14:20", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 11:14:20", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "8c7416d4-1813-47a7-9808-769c1d9cb0c0", "date": "2025-11-06", "quantity": 16505.52665, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "b16d86b3-ff35-480c-a220-8a7a14107935", "_rev": "2-354cf5599d3573bf878e6e6abd4fe914", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "registered", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:30:01", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:30:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "00e06088-d376-4a73-b4d0-cc0de5736004", "date": "2025-11-06", "quantity": 2483.056686, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "2ccf478e-ad2c-4bd5-bc54-a1e1dc14bef9", "_rev": "1-cdeafc64ec04fe16e4dd4fab0c393d8a", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-08 20:47:17", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-08 20:47:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "6c68c4f9-ab72-4e0f-bff9-31e9db967316", "date": "2025-08-19", "quantity": 7970.0, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "2ce32c6b-3d5c-4d0e-9f61-234c61388b17", "_rev": "1-cee28edcbac8e240de7edd312bc81891", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-10 15:51:25", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-10 15:51:25", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "bcd6d13c-e529-4f2d-ab7b-481458c587e2", "date": "2025-10-18", "quantity": 14576.616806, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "f0d337b6-4c9f-41d5-95ec-1f73d5a5fcdf", "_rev": "1-a2f55a960d8772234e3f58fa0d6f2839", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-13 20:45:50", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-13 20:45:50", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "544430cd-1301-43e0-8f7e-a471d9438983", "date": "2025-10-10", "quantity": 9564.931481, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "7f1bb17f-f261-423c-93a7-00065dc1e107", "_rev": "2-3f45904996af8275b0c2838089814e00", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:57:25", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:17:25", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:17:25", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7cfd7cbe-d737-41e4-ad0d-647ce267bbb4", "date": "2025-10-21", "quantity": 120130.6, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "16c1617f-aa63-4f7f-96f1-3549f0eee976", "_rev": "2-f90a21aabf591452dd54e95312710d72", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:57:55", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:19:57", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:19:57", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "cb4ea5f6-e8e3-4a50-a5c0-829c02be3ff6", "date": "2025-10-21", "quantity": 189094.51, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "39601bea-dd5a-4f75-9864-5c668f5f9fa8", "_rev": "2-24af8ec741fd12f124c4eb6d52526e83", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:57:44", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:23:50", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:23:50", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "e3adcce0-db55-4361-846c-3a52c99e8dd9", "date": "2024-12-13", "quantity": 92588.19, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "5864724f-6aa9-4711-8982-8a00ee71d635", "_rev": "2-5259916c592f99a0278b89d83eb61390", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:58:10", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:26:31", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:26:31", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "5789ef30-258b-4b2f-b8e9-1c644f3957fd", "date": "2025-10-21", "quantity": 799.8, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "40c52a2d-d7c4-43c0-9b7a-917045847ebf", "_rev": "2-ad8fd83e383ad2a09bccb4d0ae6363df", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:58:19", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:36:22", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:36:22", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ed4c9b00-efbb-41cc-8e67-13d3b0a80fd5", "date": "2025-11-14", "quantity": 8495.2, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "fa109829-f755-4fa6-b477-5ecb3f039148", "_rev": "2-e13f6896dc07bd099002743f6b811508", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:58:45", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 16:54:20", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 16:54:20", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "888377d9-545f-4573-a42d-7b93656e920c", "date": "2025-01-10", "quantity": 47037.13, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "1883ad2b-6c7a-4c5a-8ca2-d61b18c5aa68", "_rev": "2-e02e7d16f22f34a420a48ed647af44a5", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:58:59", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:00:59", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:00:59", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c47d31fa-7195-42c7-8fc6-e1be2a2df876", "date": "2022-01-20", "quantity": 6357.9, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "ed6750f4-1942-4403-a9e2-01af04f8d992", "_rev": "2-31e9fce16036ce1ef56c41b4aff05b6c", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:59:08", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:04:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:04:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "60f8d37c-efd4-464b-8d01-acdded4b6324", "date": "2024-12-18", "quantity": 22762.6, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "4da24b77-0e50-490c-bae6-f3a9e481d2c3", "_rev": "2-4401b705aee00c64ffb03e131a24fb21", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:59:16", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:18:32", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:18:32", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ad5e5bc4-3a75-43f4-afc9-918e4624b1fb", "date": "2025-10-21", "quantity": 1252.6, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "b1b2b8cd-f578-4234-aec7-c5ed368c5c22", "_rev": "2-9065c87e5a4de9a3435816c59f572168", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 10:59:32", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-14 17:23:11", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-14 17:23:11", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7a002e5c-6f3e-46a3-9924-12011f30eb97", "date": "2025-01-10", "quantity": 5492.0, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "c1fdaf39-bf66-488b-96bc-b59adaa19722", "_rev": "2-25ca0dfa8bc1f6d06557755dc35b3be8", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:03:56", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:15:31", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:15:31", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "602471ee-e4af-40c3-a5c6-d82117b9853a", "date": "2024-06-12", "quantity": 3563.04, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "aec4ab70-00ce-4e57-8fe7-1a1243fa0000", "_rev": "2-81d884504320710712344e1fb6e51f08", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:04:12", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 09:35:56", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 09:35:56", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "b5669ab4-d583-449d-8ec9-a6752b99dbbe", "date": "2024-08-13", "quantity": 7987.13, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "aff31c88-c992-46b4-a218-9c8ffd60d3f3", "_rev": "2-42a23d922139ed7d1e39f1f2efbc231f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:04:32", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:36:55", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:36:55", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7ed0fed1-4018-4086-b7e0-4a7f139ac8dc", "date": "2023-12-07", "quantity": 99.7, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "85aea909-424c-49a9-9d0f-444e64e7aa42", "_rev": "3-e64f786afd0cdbda4b693dfd68128ec0", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:40:32", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:40:32", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "e2f88f30-b118-4319-b214-553ebbe1c3ae", "date": "2025-12-09", "quantity": 34859.02, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 1}
|
||||
{"_id": "405882f1-a73e-4706-a4bb-0d8d97159868", "_rev": "1-4688199173742de820836ea003936216", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:44:57", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:44:57", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "5bd1e03e-5ab3-46f7-9ba5-12f91f500ffd", "date": "2025-12-09", "quantity": 33670.07, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "9a73dc64-f785-4e95-be84-116ec75093b1", "_rev": "1-9a06c7de27e42a6b509837728eb3d280", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:48:10", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:48:10", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "2e321d92-0a10-4a02-9bce-63cd81b669c1", "date": "2025-12-09", "quantity": 5845.4, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "9b68186d-42cc-4b33-9162-38fed63b1362", "_rev": "1-953d5e29ca58bdbbc3db68587eaad976", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:49:25", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:49:25", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ca573e09-e78e-4ae7-ae4f-347844f471a7", "date": "2025-12-09", "quantity": 4669.61, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "551e3bc0-0a57-4aa5-92fd-f16e2483ae1f", "_rev": "1-85b1d77cbe933546f0fb9e12ad6daa5e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:50:21", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:50:21", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7ed0fed1-4018-4086-b7e0-4a7f139ac8dc", "date": "2025-12-09", "quantity": 579.3, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "36f3c81f-5021-4cdd-a5fb-764688c97e25", "_rev": "1-9e1c53fca0d17ab6dc4b2038a47ef9ac", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:53:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:53:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "aff42f0d-4beb-4ed7-a519-1d9a5247d403", "date": "2025-12-09", "quantity": 831.2, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "c0c8edc4-41ff-4c82-95d0-5c1093cc1a30", "_rev": "1-a5bc63ff19bfac5dc27f00d9bfc0ebec", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:54:46", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:54:46", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c3831212-8134-4d5f-8ac8-c6c41fbbf6db", "date": "2025-12-09", "quantity": 946.83, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "7b22548d-5a05-4423-a4fb-2f12ce573ff8", "_rev": "1-30ad077effd6d9404e78ff4dbd5f45f7", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:55:41", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:55:41", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "d41b13cf-49c3-49ba-9613-e6dda9635c4e", "date": "2025-12-09", "quantity": 1196.81, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "74e4612e-ab02-4393-bce9-9b312b577f9a", "_rev": "1-5c377fdbc68084abccf74b75239ae8f0", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:56:41", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:56:41", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "b311422b-fa21-4fa3-84e0-7fd47b636bbf", "date": "2025-12-09", "quantity": 3863.62, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "ec8347ca-ee7b-4c26-955c-c738f446ccb4", "_rev": "1-e7e83def0eb3e6c68ae3d6a5656fa5e3", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 16:57:37", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 16:57:37", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "b1b1ac3a-33f5-4a1d-a1bd-191258a904c6", "date": "2025-12-09", "quantity": 2079.64, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "8ec08c96-28ae-44bf-848d-23b04966d6a4", "_rev": "1-aa0117b1675deae4bbc3e065bb64be5f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:02:57", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:02:57", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7cfd7cbe-d737-41e4-ad0d-647ce267bbb4", "date": "2025-12-09", "quantity": 303538.29, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "e3a4ea25-1920-4502-aba7-4fd94f74d599", "_rev": "1-9d8bd24188fe852282641c2f57db4b75", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:03:35", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:03:35", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "cb4ea5f6-e8e3-4a50-a5c0-829c02be3ff6", "date": "2025-12-09", "quantity": 414461.27, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "d746e630-8c4b-4ad4-905d-4ad5238bd331", "_rev": "1-342b2ab8c32da83b85da90549270376d", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:05:10", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:05:10", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "5789ef30-258b-4b2f-b8e9-1c644f3957fd", "date": "2025-12-09", "quantity": 7282.39, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "227de574-7d3f-4fae-8007-ce4c519754ed", "_rev": "1-425a94ba0fa1f1f3c51a3fe98d37f1c8", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:06:00", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:06:00", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ed4c9b00-efbb-41cc-8e67-13d3b0a80fd5", "date": "2025-12-09", "quantity": 9522.65, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "384f0919-65ab-4619-8cca-c568c2064af5", "_rev": "1-e6750800d318119ac8abb63b8260f5cd", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:07:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:07:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "888377d9-545f-4573-a42d-7b93656e920c", "date": "2025-12-09", "quantity": 57966.73, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "f51d622a-5366-4fcc-8b4a-b483fb6ab0a3", "_rev": "1-4c13c97e129111e1609cf39cc6d20531", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:07:57", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:07:57", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "c47d31fa-7195-42c7-8fc6-e1be2a2df876", "date": "2025-12-09", "quantity": 9194.43, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "c1877d1a-4dab-49ab-85ff-7a33a7c77388", "_rev": "1-a1e4731cb1e399b7991ca88d185d0159", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:09:22", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:09:22", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "60f8d37c-efd4-464b-8d01-acdded4b6324", "date": "2025-12-09", "quantity": 30256.02, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "a18aff41-7962-4c93-a78b-ba6cd886ccab", "_rev": "1-bb34a6cea9eab7349d424739bb1a5138", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:10:17", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:10:17", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ad5e5bc4-3a75-43f4-afc9-918e4624b1fb", "date": "2025-12-09", "quantity": 1782.73, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "a294d919-4ff0-4cd2-b304-f6299fec5c81", "_rev": "1-5b67dd48564affd9fd874adb7cca222f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-09 17:11:06", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-09 17:11:06", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "7a002e5c-6f3e-46a3-9924-12011f30eb97", "date": "2025-12-09", "quantity": 5531.78, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "f4f057a7-e5c5-4656-968b-2c67b98eb188", "_rev": "1-9ee4ce5cb4795275e0a3d4118fe3fa29", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 08:59:50", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 08:59:50", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "b5669ab4-d583-449d-8ec9-a6752b99dbbe", "date": "2025-12-12", "quantity": 15979.15, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "8fce86d9-c913-4f04-aee1-3783060ded2d", "_rev": "1-31a4e5d907c6ae5b304fcd45cdc0c4a5", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-29 17:23:35", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-29 17:23:35", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "5a8fd1df-4fb4-478e-adbb-621fc1194d47", "date": "2025-12-29", "quantity": 13493.9985, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "348bf39e-93da-4f4e-b922-4168894d98d6", "_rev": "1-2313121de9098ef1ac61d3494b6a027c", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-02-06 10:40:13", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:40:13", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "13c83c67-a726-4e1c-ade5-bb146a3dac4f", "date": "2025-04-26", "quantity": 2791.26702, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
{"_id": "fa695483-8132-4d1c-9600-49e930e116a0", "_rev": "1-5535efb3ada6148befd5f9c8b9455c4e", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-02-06 10:41:24", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:41:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "contract_settlement_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "5c8acfd1-9b0a-4a7a-a8f6-d54d56069d31", "date": "2025-10-18", "quantity": 2948.05175, "remark": null, "is_complete": false, "write_off_rate": null, "change_count": 0}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"_id": "86af6b07-244c-43df-b386-557d7162d6aa", "_rev": "4-9f50cd07555ee935d04b6ac20dedf226", "field_metadata": {"completed_resettlement_pop": {"approval_status": "under_review", "approval_flow_id": "868f66ad-e9bb-4e33-b7d6-494c6808e402", "edit_after_approve": true}, "actual_spec_project_reconstr": {"approval_status": "under_review", "approval_flow_id": "2b475331-f58a-45b9-ac4a-42718d3a11d5", "edit_after_approve": true}, "actual_reservoir_bottom_cleanup": {"approval_status": "under_review", "approval_flow_id": "2b475331-f58a-45b9-ac4a-42718d3a11d5", "edit_after_approve": true}, "completed_investment_amt": {"approval_status": "under_review", "approval_flow_id": "5d1928ca-46af-4911-9771-87887d69c9a0", "edit_after_approve": true}, "actual_urban_comp": {"edit_after_approve": true}, "actual_rural_comp": {"approval_status": "under_review", "approval_flow_id": "2b475331-f58a-45b9-ac4a-42718d3a11d5", "edit_after_approve": true}, "plan_resettlement_pop": {"approval_status": "under_review", "approval_flow_id": "868f66ad-e9bb-4e33-b7d6-494c6808e402"}, "plan_investment_amt": {"approval_status": "under_review", "approval_flow_id": "5d1928ca-46af-4911-9771-87887d69c9a0"}, "plan_rural_comp": {"approval_status": "under_review", "approval_flow_id": "2b475331-f58a-45b9-ac4a-42718d3a11d5"}, "plan_spec_project_reconstr": {"approval_status": "under_review", "approval_flow_id": "2b475331-f58a-45b9-ac4a-42718d3a11d5"}, "plan_reservoir_bottom_cleanup": {"approval_status": "under_review", "approval_flow_id": "2b475331-f58a-45b9-ac4a-42718d3a11d5"}}, "approval_user": null, "approval_status": "registered", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "lar", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "plan_resettlement_pop": 695, "completed_resettlement_pop": 695, "plan_investment_amt": 180801.09, "completed_investment_amt": 148418.19, "plan_urban_comp": 0.0, "actual_urban_comp": 0.0, "plan_rural_comp": 85696.63, "actual_rural_comp": 85625.9, "plan_spec_project_reconstr": 30010.09, "actual_spec_project_reconstr": 21295.2307, "plan_reservoir_bottom_cleanup": 986.82, "actual_reservoir_bottom_cleanup": 986.82}
|
||||
{"_id": "718a9883-8479-4963-a58c-234d1984b117", "_rev": "4-fb4df046ec69b45163d6c107ef86f067", "field_metadata": {"actual_reservoir_bottom_cleanup": {"approval_status": "under_review", "approval_flow_id": "1dbac8af-5a14-4ef5-a98d-ba9c856f8d05", "edit_after_approve": true}, "actual_spec_project_reconstr": {"approval_status": "under_review", "approval_flow_id": "1dbac8af-5a14-4ef5-a98d-ba9c856f8d05", "edit_after_approve": true}, "actual_urban_comp": {"edit_after_approve": true}, "completed_resettlement_pop": {"approval_status": "under_review", "approval_flow_id": "416db412-8eef-47b9-bf48-fc8c4c1f8804", "edit_after_approve": true}, "actual_rural_comp": {"approval_status": "under_review", "approval_flow_id": "1dbac8af-5a14-4ef5-a98d-ba9c856f8d05", "edit_after_approve": true}, "completed_investment_amt": {"approval_status": "under_review", "approval_flow_id": "89a3bde3-d210-49a4-948c-38be6ba5f5d0", "edit_after_approve": true}, "plan_resettlement_pop": {"approval_status": "under_review", "approval_flow_id": "416db412-8eef-47b9-bf48-fc8c4c1f8804"}, "plan_investment_amt": {"approval_status": "under_review", "approval_flow_id": "89a3bde3-d210-49a4-948c-38be6ba5f5d0"}, "plan_rural_comp": {"approval_status": "under_review", "approval_flow_id": "1dbac8af-5a14-4ef5-a98d-ba9c856f8d05"}, "plan_spec_project_reconstr": {"approval_status": "under_review", "approval_flow_id": "1dbac8af-5a14-4ef5-a98d-ba9c856f8d05"}, "plan_reservoir_bottom_cleanup": {"approval_status": "under_review", "approval_flow_id": "1dbac8af-5a14-4ef5-a98d-ba9c856f8d05"}}, "approval_user": null, "approval_status": "registered", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "lar", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "plan_resettlement_pop": 83, "completed_resettlement_pop": 83, "plan_investment_amt": 29698.24, "completed_investment_amt": 24230.31, "plan_urban_comp": 0.0, "actual_urban_comp": 0.0, "plan_rural_comp": 16689.73, "actual_rural_comp": 16644.28, "plan_spec_project_reconstr": 2726.2, "actual_spec_project_reconstr": 2726.2, "plan_reservoir_bottom_cleanup": 72.03, "actual_reservoir_bottom_cleanup": 72.03}
|
||||
@@ -0,0 +1,38 @@
|
||||
{"_id": "2be180e2-98f3-47d5-8de5-86f284fc43af", "_rev": "3-29098aefae5162e96118c4afce7fc1d2", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "9e81bc1f-d36b-442b-b0f2-d6559a1a0dee", "edit_after_approve": true}, "complete_rate": {}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "9e81bc1f-d36b-442b-b0f2-d6559a1a0dee"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "9e81bc1f-d36b-442b-b0f2-d6559a1a0dee"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "9e81bc1f-d36b-442b-b0f2-d6559a1a0dee"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "9e81bc1f-d36b-442b-b0f2-d6559a1a0dee"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:45:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "66fb4f4b-872b-420e-9d01-f392a840b5a1", "show_name": "液压式启闭机采购合同(台)", "material_type": "YQ", "contract_quantity": 17.0, "plan_start_quantity": 2.0, "complete_quantity": 12.0, "complete_rate": 70.59, "plan_start_date": "2024-06-30", "plan_complete_date": "2026-06-30", "actual_start_date": "2025-09-30", "actual_complete_date": null, "plan_node": [{"date": "2024-06-30", "quantity": 2.0, "is_audit": false}, {"date": "2026-06-30", "quantity": 17.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-09-30"}
|
||||
{"_id": "380a630b-bf59-428a-89e3-4c5c07af8e7a", "_rev": "5-394dd5e91c6e3e3004cd66765a9e9676", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "a0e2ffc3-1e46-4600-856a-84d979d266bc", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "a0e2ffc3-1e46-4600-856a-84d979d266bc"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "a0e2ffc3-1e46-4600-856a-84d979d266bc"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "a0e2ffc3-1e46-4600-856a-84d979d266bc"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "a0e2ffc3-1e46-4600-856a-84d979d266bc"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "a28a8672-c913-4113-90c9-0371f6db9342", "show_name": "桥式起重设备采购合同(台)", "material_type": "QJ", "contract_quantity": 2.0, "plan_start_quantity": 1.0, "complete_quantity": 2.0, "complete_rate": 100.0, "plan_start_date": "2025-03-31", "plan_complete_date": "2025-06-30", "actual_start_date": "2025-06-20", "actual_complete_date": "2025-05-31", "plan_node": [{"date": "2025-03-31", "quantity": 1.0, "is_audit": false}, {"date": "2025-06-30", "quantity": 2.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-05-31"}
|
||||
{"_id": "3be5e901-13cb-40ea-90e0-99b99f5cd116", "_rev": "25-fd70cc92a7315d6d4c6b17b58ac55170", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "b9f7e283-a620-42f7-ad5d-a4c25b59e677", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "b9f7e283-a620-42f7-ad5d-a4c25b59e677"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "b9f7e283-a620-42f7-ad5d-a4c25b59e677"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "b9f7e283-a620-42f7-ad5d-a4c25b59e677"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "b9f7e283-a620-42f7-ad5d-a4c25b59e677"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-27 00:00:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "640fc215-134a-49b5-a486-225fa6a0c5c5", "show_name": "卷扬式启闭机采购合同(台)", "material_type": "JQ", "contract_quantity": 12.0, "plan_start_quantity": 1.0, "complete_quantity": 9.0, "complete_rate": 75.0, "plan_start_date": "2023-12-31", "plan_complete_date": "2025-06-30", "actual_start_date": "2025-12-31", "actual_complete_date": null, "plan_node": [{"date": "2023-12-31", "quantity": 1.0, "is_audit": false}, {"date": "2024-12-31", "quantity": 9.0, "is_audit": false}, {"date": "2025-06-30", "quantity": 12.0, "is_audit": false}], "status": -1, "sort": 0, "delay_days": 242, "statistic_date": "2025-12-31"}
|
||||
{"_id": "4472248f-2ead-46d9-adca-20f0ca6a08ca", "_rev": "4-0025c592301886b768f0b0a25ab50f05", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "da13e48f-c494-4571-9422-3b348aef7245", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "da13e48f-c494-4571-9422-3b348aef7245"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "da13e48f-c494-4571-9422-3b348aef7245"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "da13e48f-c494-4571-9422-3b348aef7245"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "da13e48f-c494-4571-9422-3b348aef7245"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "5b7984d7-c947-424f-9694-8f17d45b86b4", "show_name": "钢筋采购合同(吨)", "material_type": "GJ", "contract_quantity": 79210.0, "plan_start_quantity": 5121.28, "complete_quantity": 72999.566, "complete_rate": 92.16, "plan_start_date": "2024-08-10", "plan_complete_date": "2026-12-31", "actual_start_date": "2025-10-10", "actual_complete_date": null, "plan_node": [{"date": "2024-08-10", "quantity": 5121.28, "is_audit": false}, {"date": "2026-12-31", "quantity": 79210.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-10"}
|
||||
{"_id": "4b5a301c-ac3a-4f72-90d9-48113d07abe3", "_rev": "4-66e4e9d7e30c383ac6b2867d38f13e69", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "52ac662d-6518-4f0e-a57a-92995f5dfd28", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "52ac662d-6518-4f0e-a57a-92995f5dfd28"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "52ac662d-6518-4f0e-a57a-92995f5dfd28"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "52ac662d-6518-4f0e-a57a-92995f5dfd28"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "52ac662d-6518-4f0e-a57a-92995f5dfd28"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "8dde2df6-ae27-4e61-ad80-62dbb7c93ec1", "show_name": "主变压器采购合同(台)", "material_type": "ZB", "contract_quantity": 6.0, "plan_start_quantity": 1.0, "complete_quantity": 5.0, "complete_rate": 83.33, "plan_start_date": "2024-12-31", "plan_complete_date": "2026-03-31", "actual_start_date": "2025-11-30", "actual_complete_date": null, "plan_node": [{"date": "2024-12-31", "quantity": 1.0, "is_audit": false}, {"date": "2026-03-31", "quantity": 6.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-11-30"}
|
||||
{"_id": "51cb0e26-cda5-4d7b-8f8f-4ff040e01860", "_rev": "1-3a8528ed10837fd887fc53f2895c0533", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "bf665bb5-0d84-43ea-80ce-a8b575d75d62", "show_name": "发电机出口断路器采购合同(台)", "material_type": "JD", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "590e8e7d-1239-4639-a00a-885d075db20b", "_rev": "4-40aa4192c164382ebd61a1241cc6daee", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "7976fb4d-ebf0-4456-a3ee-d33834e6b085", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "7976fb4d-ebf0-4456-a3ee-d33834e6b085"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "7976fb4d-ebf0-4456-a3ee-d33834e6b085"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "7976fb4d-ebf0-4456-a3ee-d33834e6b085"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "7976fb4d-ebf0-4456-a3ee-d33834e6b085"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "19c887cb-a0c7-4dd9-9c37-63d53e049ab8", "show_name": "高压厂用变采购合同(台)", "material_type": "GB", "contract_quantity": 49.0, "plan_start_quantity": 2.0, "complete_quantity": 49.0, "complete_rate": 100.0, "plan_start_date": "2025-01-31", "plan_complete_date": "2025-09-30", "actual_start_date": "2025-09-30", "actual_complete_date": "2025-09-30", "plan_node": [{"date": "2025-01-31", "quantity": 2.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 49.0, "is_audit": false}], "status": 0, "sort": 0, "delay_days": 0, "statistic_date": "2025-09-30"}
|
||||
{"_id": "69b8803d-6cd3-4301-9900-03b94d9cac77", "_rev": "4-90b25f9a9af9d55d3d68026d4018dc0b", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "6444d966-29f1-4d22-8232-25fa6329ca5a", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "6444d966-29f1-4d22-8232-25fa6329ca5a"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "6444d966-29f1-4d22-8232-25fa6329ca5a"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "6444d966-29f1-4d22-8232-25fa6329ca5a"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "6444d966-29f1-4d22-8232-25fa6329ca5a"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "cab2e475-6420-43f1-ac0b-f1d60032714d", "show_name": "水轮机采购合同(台)", "material_type": "SJ", "contract_quantity": 6.0, "plan_start_quantity": 1.0, "complete_quantity": 6.0, "complete_rate": 100.0, "plan_start_date": "2024-07-31", "plan_complete_date": "2025-09-30", "actual_start_date": "2025-09-30", "actual_complete_date": "2025-09-30", "plan_node": [{"date": "2024-07-31", "quantity": 1.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 6.0, "is_audit": false}], "status": 0, "sort": 0, "delay_days": 0, "statistic_date": "2025-09-30"}
|
||||
{"_id": "6fd101a2-2047-465d-a905-455f515b9faf", "_rev": "3-9a4f1196165ad83667f3205c119f82f8", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "29a7e9d8-ffe8-43e7-8842-8b28d3c1147b", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "29a7e9d8-ffe8-43e7-8842-8b28d3c1147b"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "29a7e9d8-ffe8-43e7-8842-8b28d3c1147b"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "29a7e9d8-ffe8-43e7-8842-8b28d3c1147b"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "29a7e9d8-ffe8-43e7-8842-8b28d3c1147b"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "37b54e2a-c159-4cca-a64a-13f379ff64aa", "show_name": "水泥采购合同(吨)", "material_type": "SN", "contract_quantity": 551000.0, "plan_start_quantity": 250.0, "complete_quantity": 527261.0, "complete_rate": 95.69, "plan_start_date": "2021-05-10", "plan_complete_date": "2026-12-31", "actual_start_date": "2025-10-10", "actual_complete_date": null, "plan_node": [{"date": "2021-05-10", "quantity": 250.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 551000.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": null, "statistic_date": "2025-10-10"}
|
||||
{"_id": "79a8cbb5-5081-476f-81bf-50cac4570bd4", "_rev": "3-13c4de9ae8600a810bdc4343f43cc30d", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "c1b9aaf6-b2a8-40d6-b610-e71c032acd9e", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "c1b9aaf6-b2a8-40d6-b610-e71c032acd9e"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "c1b9aaf6-b2a8-40d6-b610-e71c032acd9e"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "c1b9aaf6-b2a8-40d6-b610-e71c032acd9e"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "c1b9aaf6-b2a8-40d6-b610-e71c032acd9e"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "22b8d43f-3ea2-412a-a5b0-5329b8998d6f", "show_name": "发电机采购合同(台)", "material_type": "DJ", "contract_quantity": 6.0, "plan_start_quantity": 1.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": "2024-06-30", "plan_complete_date": "2025-08-31", "actual_start_date": null, "actual_complete_date": null, "plan_node": [{"date": "2024-06-30", "quantity": 1.0, "is_audit": false}, {"date": "2025-08-31", "quantity": 6.0, "is_audit": false}], "status": -1, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "8a9dfa27-d1d1-40d6-8a67-70ef84c92250", "_rev": "4-434dd90557ca26982894674279fda22b", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "c4d72d20-3175-461b-be43-6bcc5ff72cda", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "c4d72d20-3175-461b-be43-6bcc5ff72cda"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "c4d72d20-3175-461b-be43-6bcc5ff72cda"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "c4d72d20-3175-461b-be43-6bcc5ff72cda"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "c4d72d20-3175-461b-be43-6bcc5ff72cda"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "b8822b9e-4511-497f-98cc-b45be77b1e96", "show_name": "高压厂用电配电系统采购合同(套)", "material_type": "GP", "contract_quantity": 140.0, "plan_start_quantity": 40.0, "complete_quantity": 140.0, "complete_rate": 100.0, "plan_start_date": "2025-01-01", "plan_complete_date": "2025-09-30", "actual_start_date": "2025-09-15", "actual_complete_date": "2025-09-15", "plan_node": [{"date": "2025-01-01", "quantity": 40.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 140.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-09-15"}
|
||||
{"_id": "a1e41634-c82d-4b9f-9993-e1ab6c768c8d", "_rev": "79-6f03a795059e891618970f729ba00ae4", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "671723c5-6af5-450f-b57d-66acb2ee6441", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "671723c5-6af5-450f-b57d-66acb2ee6441"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "671723c5-6af5-450f-b57d-66acb2ee6441"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "671723c5-6af5-450f-b57d-66acb2ee6441"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "671723c5-6af5-450f-b57d-66acb2ee6441"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "58c1f591-ba44-4452-b8db-4f9e7a9ea9f2", "show_name": "励磁系统采购合同(套)", "material_type": "LC", "contract_quantity": 6.0, "plan_start_quantity": 1.0, "complete_quantity": 4.0, "complete_rate": 66.67, "plan_start_date": "2025-03-20", "plan_complete_date": "2026-01-31", "actual_start_date": "2025-03-22", "actual_complete_date": null, "plan_node": [{"date": "2025-03-20", "quantity": 1.0, "is_audit": false}, {"date": "2025-03-21", "quantity": 2.0, "is_audit": false}, {"date": "2025-05-15", "quantity": 3.0, "is_audit": false}, {"date": "2025-06-15", "quantity": 4.0, "is_audit": false}, {"date": "2025-12-15", "quantity": 5.0, "is_audit": false}, {"date": "2026-01-31", "quantity": 6.0, "is_audit": false}], "status": -1, "sort": 0, "delay_days": 74, "statistic_date": "2025-06-27"}
|
||||
{"_id": "b5913057-001a-4353-a368-4ebdd345e2b9", "_rev": "4-04cbdd3d6ec448dfc8e080bdf59a5b2d", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "95a53a49-a731-4578-b2ef-89b840dab254", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "95a53a49-a731-4578-b2ef-89b840dab254"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "95a53a49-a731-4578-b2ef-89b840dab254"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "95a53a49-a731-4578-b2ef-89b840dab254"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "95a53a49-a731-4578-b2ef-89b840dab254"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "0a5f071c-101c-45fc-92dc-f828500a00bb", "show_name": "低压厂用电配电系统采购合同(套)", "material_type": "DP", "contract_quantity": 204.0, "plan_start_quantity": 50.0, "complete_quantity": 204.0, "complete_rate": 100.0, "plan_start_date": "2025-01-01", "plan_complete_date": "2025-09-30", "actual_start_date": "2025-09-15", "actual_complete_date": "2025-09-15", "plan_node": [{"date": "2025-01-01", "quantity": 50.0, "is_audit": false}, {"date": "2025-09-30", "quantity": 204.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-09-15"}
|
||||
{"_id": "d0282a80-beba-4241-94ae-2817cd9c43a9", "_rev": "1-4cd1e07786cf798febb2b9e5599aa694", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "f509a975-7c1f-4fbb-bbda-2f85eaed1b3d", "show_name": "调速器及其附属设备采购合同(套)", "material_type": "TS", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "e1ea10b7-a4c0-497c-9e69-b33172630ad5", "_rev": "1-9ff77c5f16df7b86d7067078d720e9a4", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "a2d49172-e04a-4cca-b801-fc7b0d6d0fac", "show_name": "计算机监控系统采购合同(套)", "material_type": "JK", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "ed9cff63-3598-404c-9034-f39260764383", "_rev": "5-5d7bc62fc44e329ccdcb9e87a9056dd4", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "916e7152-8b6c-4aef-884f-68b3468478e9", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "916e7152-8b6c-4aef-884f-68b3468478e9"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "916e7152-8b6c-4aef-884f-68b3468478e9"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "916e7152-8b6c-4aef-884f-68b3468478e9"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "f28cd32a-564b-4a7c-926f-7d138f6c2439", "show_name": "GIS系统采购合同(套)", "material_type": "GS", "contract_quantity": 1.0, "plan_start_quantity": 0.0, "complete_quantity": 1.0, "complete_rate": 100.0, "plan_start_date": "2025-04-15", "plan_complete_date": "2025-10-31", "actual_start_date": "2025-09-30", "actual_complete_date": "2025-09-30", "plan_node": [{"date": "2025-04-15", "quantity": 0.0, "is_audit": false}, {"date": "2025-10-31", "quantity": 1.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-09-30"}
|
||||
{"_id": "f8efc1a4-2d2a-410a-ab99-7f06a003e848", "_rev": "4-e9284b47914b38f12abcf1afddf9443b", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "d7df5ffe-1e8c-454a-9bf6-6b47756f78e2", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "d7df5ffe-1e8c-454a-9bf6-6b47756f78e2"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "d7df5ffe-1e8c-454a-9bf6-6b47756f78e2"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "d7df5ffe-1e8c-454a-9bf6-6b47756f78e2"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "d7df5ffe-1e8c-454a-9bf6-6b47756f78e2"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "f95333ee-5f6f-421c-94ce-7edc063b8c62", "show_name": "外加剂采购合同(吨)", "material_type": "YJ", "contract_quantity": 10700.0, "plan_start_quantity": 52.25, "complete_quantity": 9719.98, "complete_rate": 90.84, "plan_start_date": "2021-09-11", "plan_complete_date": "2026-12-31", "actual_start_date": "2025-10-11", "actual_complete_date": null, "plan_node": [{"date": "2021-09-11", "quantity": 52.25, "is_audit": false}, {"date": "2026-12-31", "quantity": 10700.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-10"}
|
||||
{"_id": "fb0d3b57-cf9e-406f-865c-5e1bdb071c1c", "_rev": "4-4006c828ae5e140e32e099509a2c96f7", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "804bf40a-bd7a-4e80-bcb9-37259e81e7de", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "804bf40a-bd7a-4e80-bcb9-37259e81e7de"}, "plan_start_quantity": {"approval_status": "under_review", "approval_flow_id": "804bf40a-bd7a-4e80-bcb9-37259e81e7de"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "804bf40a-bd7a-4e80-bcb9-37259e81e7de"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "804bf40a-bd7a-4e80-bcb9-37259e81e7de"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:01", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "1974b17f-e35f-4053-bbc8-3c1cee0a65ce", "show_name": "粉煤灰采购合同(吨)", "material_type": "FM", "contract_quantity": 102569.0, "plan_start_quantity": 3000.0, "complete_quantity": 79178.58, "complete_rate": 77.2, "plan_start_date": "2025-02-10", "plan_complete_date": "2026-12-31", "actual_start_date": "2025-10-10", "actual_complete_date": null, "plan_node": [{"date": "2025-02-10", "quantity": 3000.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 102569.0, "is_audit": false}], "status": 1, "sort": 0, "delay_days": 0, "statistic_date": "2025-12-10"}
|
||||
{"_id": "1345b58c-9229-49ef-8d87-6905706cc937", "_rev": "1-d16b9f723aeb86e6c768136dc1e96722", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "bf9ee1f3-eb6f-495c-a2db-6c95ecf3f8d8", "show_name": "桥式起重设备采购合同(台)", "material_type": "QJ", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "236c2610-f210-450a-846b-2241b2fd07f4", "_rev": "113-d3eab909b8403977755357eca7dd1313", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "b9dad54b-68d4-4a58-b099-8f27dd5217d5", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "b9dad54b-68d4-4a58-b099-8f27dd5217d5"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "b9dad54b-68d4-4a58-b099-8f27dd5217d5"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "b9dad54b-68d4-4a58-b099-8f27dd5217d5"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "8cb77da2-1460-42b0-9ca4-7aa5afa58b99", "show_name": "钢筋采购合同(吨)", "material_type": "GJ", "contract_quantity": 51161.0, "plan_start_quantity": 0.0, "complete_quantity": 12446.639, "complete_rate": 24.33, "plan_start_date": "2024-07-11", "plan_complete_date": "2026-12-31", "actual_start_date": "2025-11-08", "actual_complete_date": null, "plan_node": [{"date": "2024-07-11", "quantity": 0.0, "is_audit": false}, {"date": "2025-04-10", "quantity": 1209.0, "is_audit": false}, {"date": "2025-05-10", "quantity": 5011.0, "is_audit": false}, {"date": "2025-06-10", "quantity": 9032.0, "is_audit": false}, {"date": "2025-07-10", "quantity": 12483.0, "is_audit": false}, {"date": "2025-08-10", "quantity": 14967.0, "is_audit": false}, {"date": "2025-09-10", "quantity": 18642.0, "is_audit": false}, {"date": "2025-10-10", "quantity": 21432.0, "is_audit": false}, {"date": "2025-11-10", "quantity": 24301.0, "is_audit": false}, {"date": "2026-12-31", "quantity": 51161.0, "is_audit": false}], "status": -1, "sort": 0, "delay_days": 201, "statistic_date": "2025-11-08"}
|
||||
{"_id": "2cca0365-375c-4252-8e7b-74cc7d0c4fbf", "_rev": "1-5ef6f5782db42b60eedffb689b5894af", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "b4c2ffab-2c38-49cd-a065-31b9a4b22d1b", "show_name": "闸门及拦污栅采购合同(扇)", "material_type": "ZM", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "408afe66-17b5-435a-9efe-3a9b7b5a8093", "_rev": "1-6793ed43db282535ef56c41be6b888d3", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "829d3033-6bb1-42eb-88d3-fc1f01985751", "show_name": "高压厂用变采购合同(台)", "material_type": "GB", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "4d5468f4-8e78-48e3-8c85-6f540874dab9", "_rev": "1-0d995236abab547617f4f9dbb07f8fa5", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "864c50af-64d8-4278-a1fc-a30804a91d3c", "show_name": "外加剂采购合同(吨)", "material_type": "YJ", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "4e819a35-7a8e-4c17-b2ce-66981acfa2ba", "_rev": "1-2bb5005b4f5259faed11e0cce11b2340", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "74c610c4-4268-4143-a1b4-d1e30f450997", "show_name": "水轮机采购合同(台)", "material_type": "SJ", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "506a1188-0c20-44fc-8dba-1a36a074bfea", "_rev": "113-45c79b92146db5920bef980c9770cd4c", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "494863df-24fd-4c9a-b034-71bb98ca3845", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "494863df-24fd-4c9a-b034-71bb98ca3845"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "494863df-24fd-4c9a-b034-71bb98ca3845"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "494863df-24fd-4c9a-b034-71bb98ca3845"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "07d0c522-598c-4a19-a35d-b18bbd152ce1", "show_name": "粉煤灰采购合同(吨)", "material_type": "FM", "contract_quantity": 60000.0, "plan_start_quantity": 0.0, "complete_quantity": 6742.84, "complete_rate": 11.24, "plan_start_date": "2024-12-01", "plan_complete_date": "2027-05-31", "actual_start_date": "2025-11-03", "actual_complete_date": null, "plan_node": [{"date": "2024-12-01", "quantity": 0.0, "is_audit": false}, {"date": "2025-04-10", "quantity": 1060.0, "is_audit": false}, {"date": "2025-05-10", "quantity": 2807.0, "is_audit": false}, {"date": "2025-06-10", "quantity": 5654.0, "is_audit": false}, {"date": "2025-07-10", "quantity": 8337.0, "is_audit": false}, {"date": "2025-08-10", "quantity": 10498.0, "is_audit": false}, {"date": "2025-09-10", "quantity": 11838.0, "is_audit": false}, {"date": "2025-10-10", "quantity": 13052.0, "is_audit": false}, {"date": "2027-05-31", "quantity": 60000.0, "is_audit": false}], "status": -1, "sort": 0, "delay_days": 232, "statistic_date": "2025-11-03"}
|
||||
{"_id": "508ff179-5731-4f66-a7e3-61a2db61ec74", "_rev": "1-6a88d34073f119609aefcca572a471f7", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "6425478f-d383-4466-a387-d9c927a7c8d9", "show_name": "高压厂用电配电系统采购合同(套)", "material_type": "GP", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "67d14c68-0b8c-4abd-aa71-0215eb18009e", "_rev": "1-80dfc2e395143ef4793976b472220f6e", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "86c5bd6f-7737-4aca-b3af-330ab3c9208b", "show_name": "发电机出口断路器采购合同(台)", "material_type": "JD", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "72d999de-7cf0-451f-873e-eaacf74af3f4", "_rev": "1-5ec503bcc002488d5104c55e34dff4cd", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "e00871cb-6404-4909-b0ce-db0baecae803", "show_name": "GIS系统采购合同(套)", "material_type": "GS", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "731a77db-06c9-4af4-864f-ea4cd046c5b2", "_rev": "1-fa3985ddce76666672eb7de9bbc0074e", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "89bf5647-594a-441f-9ea5-e9105f50dd78", "show_name": "调速器及其附属设备采购合同(套)", "material_type": "TS", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "88519b6d-eb3e-4f53-8233-aac4a6da3c1b", "_rev": "1-81e154af0cd7492d0154f89d82fd47b3", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "92e3de18-354c-4acf-9cb5-58ee55708fbd", "show_name": "低压厂用电配电系统采购合同(套)", "material_type": "DP", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "8d45e87d-91a2-469b-b719-e9dee413119f", "_rev": "1-e95d2cbecc391f70a67f4cca4ab4096a", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "031687f4-e525-4ac4-95f5-5d1343dbad26", "show_name": "计算机监控系统采购合同(套)", "material_type": "JK", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "8db5038f-cc59-4527-ae42-420ef51eefbd", "_rev": "1-9dc2959e5a067701f1ac4c7766ff8d74", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "039c3d1b-9bbe-40d9-baae-5db156785101", "show_name": "主变压器采购合同(台)", "material_type": "ZB", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "8dea3bb6-590a-42ca-a3c8-e1001f8ce88b", "_rev": "1-3f70ee24276fc014d1b06f2c03544f24", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "8ca9f6af-d93a-4274-9651-3325ea1a47a2", "show_name": "液压式启闭机采购合同(台)", "material_type": "YQ", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "bfa7ea83-b061-4cb2-b6a3-99b92e14d125", "_rev": "1-26ab0f8a54c4ca4b78ac335280824faa", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "2cd96d17-4068-43a9-b856-07c2e071e8cc", "show_name": "卷扬式启闭机采购合同(台)", "material_type": "JQ", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "c1620e5c-b167-436a-874b-ab57e57254f0", "_rev": "113-4c772493dd8ef3504aaceb21b97432e2", "field_metadata": {"plan_node": {"approval_status": "under_review", "approval_flow_id": "554e7584-11bf-45ba-ae8e-f8f207c1a7c6", "edit_after_approve": true}, "plan_start_date": {"approval_status": "under_review", "approval_flow_id": "554e7584-11bf-45ba-ae8e-f8f207c1a7c6"}, "plan_complete_date": {"approval_status": "under_review", "approval_flow_id": "554e7584-11bf-45ba-ae8e-f8f207c1a7c6"}, "contract_quantity": {"approval_status": "under_review", "approval_flow_id": "554e7584-11bf-45ba-ae8e-f8f207c1a7c6"}}, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-27 00:00:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "8b3bd771-1b7f-42f6-adb6-4bae6c765a3f", "show_name": "水泥采购合同(吨)", "material_type": "SN", "contract_quantity": 403123.0, "plan_start_quantity": 0.0, "complete_quantity": 71441.0, "complete_rate": 17.72, "plan_start_date": "2024-07-11", "plan_complete_date": "2027-09-10", "actual_start_date": "2025-11-07", "actual_complete_date": null, "plan_node": [{"date": "2024-07-11", "quantity": 0.0, "is_audit": false}, {"date": "2025-04-10", "quantity": 4429.0, "is_audit": false}, {"date": "2025-05-10", "quantity": 16966.0, "is_audit": false}, {"date": "2025-06-10", "quantity": 35690.0, "is_audit": false}, {"date": "2025-07-10", "quantity": 53151.0, "is_audit": false}, {"date": "2025-08-10", "quantity": 69257.0, "is_audit": false}, {"date": "2025-09-10", "quantity": 81561.0, "is_audit": false}, {"date": "2025-10-10", "quantity": 92693.0, "is_audit": false}, {"date": "2025-11-10", "quantity": 103435.0, "is_audit": false}, {"date": "2027-09-10", "quantity": 403123.0, "is_audit": false}], "status": -1, "sort": 0, "delay_days": 170, "statistic_date": "2025-11-07"}
|
||||
{"_id": "df971b61-9d14-400a-98f2-12cfc2fbb197", "_rev": "1-d0e5672a6d4ba272f901accd8a1f8380", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "d13a7aec-9cd8-4cf6-ac21-ccd1b79bcc55", "show_name": "励磁系统采购合同(套)", "material_type": "LC", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "e524e1c2-5e17-416a-8297-2507f4dcda47", "_rev": "1-90308047bc8ece1151306a8a9c843355", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "9e112f2d-60c3-4429-9861-e6348d0d6fd4", "show_name": "发电机采购合同(台)", "material_type": "DJ", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
{"_id": "eedec804-f388-4acb-a59a-1b6adb44ae3e", "_rev": "1-d2c32a5e8481e44f327d769cb02c8e84", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "e312644b-2e3e-4179-8de0-0183e2c72cf4", "show_name": "低压厂用变采购合同(台)", "material_type": "DB", "contract_quantity": 0.0, "plan_start_quantity": 0.0, "complete_quantity": 0.0, "complete_rate": 0.0, "plan_start_date": null, "plan_complete_date": null, "actual_start_date": null, "actual_complete_date": null, "plan_node": [], "status": null, "sort": 0, "delay_days": null, "statistic_date": null}
|
||||
@@ -0,0 +1,21 @@
|
||||
{"_id": "e996f4ef-3cff-476c-9b1b-a3d940ac24d6", "_rev": "1-74b772edd1aa6609404d1234178f99d5", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 10:24:28", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 10:24:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "506a1188-0c20-44fc-8dba-1a36a074bfea", "date": "2025-11-03", "rate": null, "quantity": 6742.84, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "c5b0edd9-fb7c-4712-8172-841de419ad29", "_rev": "1-65d090e77ba4ca3073a08bab9d70b949", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 10:41:04", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 10:41:04", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "236c2610-f210-450a-846b-2241b2fd07f4", "date": "2025-11-08", "rate": null, "quantity": 12446.639, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "bbaf696f-d1f8-4b2b-839f-01dc2ebc0d81", "_rev": "1-b7d61215512b3c198b3f877ae4a8d3c4", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-09 10:49:24", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-11-09 10:49:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "parent_id": "c1620e5c-b167-436a-874b-ab57e57254f0", "date": "2025-11-07", "rate": null, "quantity": 71441.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "b64cf277-8fb1-47e2-8582-67d8688f9eea", "_rev": "2-b67093eb835a3fb1a1430570bd49c1d3", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:05:17", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 16:29:54", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 16:29:54", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "f8efc1a4-2d2a-410a-ab99-7f06a003e848", "date": "2025-10-11", "rate": null, "quantity": 9286.52, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "900955b8-9913-41ab-bec7-4607bb44a427", "_rev": "2-22f136337b44b16ffdad6ff592e8c37f", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:05:03", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 16:55:29", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 16:55:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "6fd101a2-2047-465d-a905-455f515b9faf", "date": "2025-10-10", "rate": null, "quantity": 527261.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "4ba44092-d5bf-488f-bea4-6977dbf816b1", "_rev": "2-68525949eee43c9c325ee868ed0dd89b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:05:10", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 17:08:05", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 17:08:05", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "fb0d3b57-cf9e-406f-865c-5e1bdb071c1c", "date": "2025-10-10", "rate": null, "quantity": 65581.89, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "724391e6-984d-4a5a-b884-5bdd047adc2c", "_rev": "2-3a4663c62f6b87782f25ff71468c1537", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:04:52", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 17:25:57", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 17:25:57", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "4472248f-2ead-46d9-adca-20f0ca6a08ca", "date": "2025-10-10", "rate": null, "quantity": 69376.169, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "edfb6f6a-cdd3-44a1-a8ce-9b0c5e9e9ecf", "_rev": "2-84415a879a93195d93a18fda22bda3c4", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-11-15 21:18:51", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:15:21", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:15:21", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "a1e41634-c82d-4b9f-9993-e1ab6c768c8d", "date": "2025-03-22", "rate": null, "quantity": 2.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "7c4df839-2ccb-4d24-b6b1-7093718d82b6", "_rev": "2-25f9df799fea78cff8021ef2ca61287b", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "pending_confirm", "approval_comment": null, "approval_time": "2025-12-04 11:05:40", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-15 21:19:18", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-15 21:19:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "a1e41634-c82d-4b9f-9993-e1ab6c768c8d", "date": "2025-06-27", "rate": null, "quantity": 4.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "622efe4b-fc6b-4324-8e9b-10438b33b171", "_rev": "1-cca22d4092b04fb3eec49be4324b178a", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 09:49:15", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 09:49:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "69b8803d-6cd3-4301-9900-03b94d9cac77", "date": "2025-09-30", "rate": null, "quantity": 6.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "15e78e52-3d06-49f0-a1b1-e75f939d2fd4", "_rev": "1-edf441724f45590a70a533e63f98d249", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 10:14:45", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 10:14:45", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "ed9cff63-3598-404c-9034-f39260764383", "date": "2025-09-30", "rate": null, "quantity": 1.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "ac3135ba-1663-4f58-97e2-a1633678c636", "_rev": "1-9503d136e38cf12745e7756ca037e8cc", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 11:19:49", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 11:19:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "590e8e7d-1239-4639-a00a-885d075db20b", "date": "2025-09-30", "rate": null, "quantity": 49.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "798c7e72-3eec-4ec9-81f5-42627c779f81", "_rev": "1-7006601c5ccf9d45db93b7638903e529", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 11:28:01", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 11:28:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "8a9dfa27-d1d1-40d6-8a67-70ef84c92250", "date": "2025-09-15", "rate": null, "quantity": 140.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "099b1241-de73-4553-a052-a00e45a34459", "_rev": "1-041bf659fed17e22b7a1f13c715ae4ea", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 11:33:15", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 11:33:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "b5913057-001a-4353-a368-4ebdd345e2b9", "date": "2025-09-15", "rate": null, "quantity": 204.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "49c7bd65-201a-4b05-b998-720a91408539", "_rev": "3-2dd259c293f99e71cf8f8ad2a10e70cf", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-12-12 11:34:05", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-12 11:34:05", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "380a630b-bf59-428a-89e3-4c5c07af8e7a", "date": "2025-05-31", "rate": null, "quantity": 2.0, "status": null, "remark": null, "is_complete": null, "change_count": 1}
|
||||
{"_id": "2dae8809-3dc4-4ee4-8e56-96179e145f19", "_rev": "1-0e5458242354ac5446346981058fc450", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-01-08 09:53:24", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-01-08 09:53:24", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "4472248f-2ead-46d9-adca-20f0ca6a08ca", "date": "2025-12-10", "rate": null, "quantity": 72999.566, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "b65091fe-5475-419b-a769-f12b58ea8733", "_rev": "1-490e07b2805f8686f0deac8f3ca54d12", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-01-08 09:55:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-01-08 09:55:48", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "f8efc1a4-2d2a-410a-ab99-7f06a003e848", "date": "2025-12-10", "rate": null, "quantity": 9719.98, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "8dc40ad4-bfdf-4b78-bd84-f608fffec9ca", "_rev": "1-39f2378c103ff94831df0120ad6598b4", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-01-08 09:56:16", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-01-08 09:56:16", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "fb0d3b57-cf9e-406f-865c-5e1bdb071c1c", "date": "2025-12-10", "rate": null, "quantity": 79178.58, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "d32c9e42-b999-4eaf-aef1-a34c75ee9623", "_rev": "1-171f5bcc26119b06596060dc675c5948", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-01-08 10:11:12", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-01-08 10:11:12", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "4b5a301c-ac3a-4f72-90d9-48113d07abe3", "date": "2025-11-30", "rate": null, "quantity": 5.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "d4adab1d-8675-4ae8-9897-c7d6a9fa4cc4", "_rev": "1-2c531e4d17dd7d02d9082674d8a15135", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-02-06 10:44:12", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:44:12", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "3be5e901-13cb-40ea-90e0-99b99f5cd116", "date": "2025-12-31", "rate": null, "quantity": 9.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
{"_id": "26a5179f-2af7-44c9-a952-f01e4bbcdf1e", "_rev": "1-13ea14fdd87ea7fc59448c20b4c62b91", "field_metadata": null, "confirmation_user": null, "confirmation_time": null, "confirmation_comment": null, "approval_user": null, "approval_status": "under_review", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2026-02-06 10:45:02", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2026-02-06 10:45:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "material_detail", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "parent_id": "2be180e2-98f3-47d5-8de5-86f284fc43af", "date": "2025-09-30", "rate": null, "quantity": 12.0, "status": null, "remark": null, "is_complete": null, "change_count": 0}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"_id": "3e39e18e-f7de-4fd4-9fe6-f81e83820de8", "_rev": "1-55451262b899a939de3396f007f31df6", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "personnel", "code": "personnel", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "contract_id": "b4fc129a-795f-42eb-ba2a-2f2e2a0c30b7", "show_name": "人员配置(人)", "status": null, "plan_attendance": 0, "actual_daily_attendance": 0, "attendance_rate": 0.0, "statistic_date": null, "plan_exit_date": null, "actual_exit_date": null, "plan_node": [], "plan_start_date": null, "plan_start_quantity": 0, "actual_start_date": null, "actual_start_quantity": null}
|
||||
{"_id": "2006708a-dae4-4874-9207-22889cf2c886", "_rev": "1-a0ec39289a4ae9b30c5eb08039791dc2", "field_metadata": {"plan_node": {"edit_after_approve": true}}, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "personnel", "code": "personnel", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "contract_id": "b16ab690-a318-4927-a165-0f2b92759922", "show_name": "人员配置(人)", "status": null, "plan_attendance": 0, "actual_daily_attendance": 0, "attendance_rate": 0.0, "statistic_date": null, "plan_exit_date": null, "actual_exit_date": null, "plan_node": [], "plan_start_date": null, "plan_start_quantity": 0, "actual_start_date": null, "actual_start_quantity": null}
|
||||
@@ -0,0 +1,40 @@
|
||||
{"_id": "006774a3-5d58-48f6-86a8-74aabc0027ab", "_rev": "3-10d3ab8d3fb7284d37adff3bcb63a28d", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "eb314157-2d54-42ec-99b9-864f65a6aa66"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "eb314157-2d54-42ec-99b9-864f65a6aa66"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "eb314157-2d54-42ec-99b9-864f65a6aa66"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "KYPF", "name": "可研批复", "is_acquired": 1, "acquire_date": "2016-08-10", "is_exist": true}
|
||||
{"_id": "0193115d-9954-44ef-bc31-6a4d6826297f", "_rev": "3-297bf320c0a4e274e94152446980d2fa", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "63264c26-9b04-4174-a59e-9d07b5b3df27"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "63264c26-9b04-4174-a59e-9d07b5b3df27"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "63264c26-9b04-4174-a59e-9d07b5b3df27"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "HSBPF", "name": "环水保“三同时”批复", "is_acquired": 1, "acquire_date": "2016-04-25", "is_exist": true}
|
||||
{"_id": "042735f7-7bfa-47f3-b3b4-172c867a2c86", "_rev": "3-030f2d0e1263556aca9d71446af8ef0c", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "8d157a6e-fb45-467c-97ed-3f1f56178178"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "8d157a6e-fb45-467c-97ed-3f1f56178178"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "8d157a6e-fb45-467c-97ed-3f1f56178178"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "WSTS", "name": "无水调试", "is_acquired": 1, "acquire_date": "2025-10-30", "is_exist": true}
|
||||
{"_id": "178c4484-a6ea-4382-a08a-0ac58f1f6bac", "_rev": "3-45fc07da60acddaababdcece8a5007c6", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "1e976667-25df-41a2-9605-eea6b74d6821"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "1e976667-25df-41a2-9605-eea6b74d6821"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "1e976667-25df-41a2-9605-eea6b74d6821"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "ZZDZ", "name": "转子吊装", "is_acquired": 1, "acquire_date": "2025-06-13", "is_exist": true}
|
||||
{"_id": "1bd24566-c05e-496b-8139-60b0f6cba678", "_rev": "3-73d39eb555220ba09958650c1c7edf6b", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "daf9b2b8-97c4-4470-8617-0de4cb5db5c9"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "daf9b2b8-97c4-4470-8617-0de4cb5db5c9"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "daf9b2b8-97c4-4470-8617-0de4cb5db5c9"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "YDPF", "name": "用地批复", "is_acquired": 1, "acquire_date": "2020-04-01", "is_exist": true}
|
||||
{"_id": "235723e5-508a-4bee-aebc-c8e68a953609", "_rev": "3-4b86774b992790d1cf4dde0bc8d225a5", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "5d5ae900-2bad-44bb-916e-575695c0ba32"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "5d5ae900-2bad-44bb-916e-575695c0ba32"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "5d5ae900-2bad-44bb-916e-575695c0ba32"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "DXCFKW", "name": "地下厂房开挖", "is_acquired": 1, "acquire_date": "2020-04-01", "is_exist": true}
|
||||
{"_id": "2d200207-4eaf-4147-913e-08a10618c230", "_rev": "1-a69a5a38c186bbc619cc89eb2fcfa3cc", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "ZLJDBA", "name": "质量监督备案", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "5653da2c-a534-4df3-a748-e16f705eb793", "_rev": "3-da6160ec2f0390cd2303364e7aa7c644", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "ef2988a6-dff3-4c80-a346-380241a35991"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "ef2988a6-dff3-4c80-a346-380241a35991"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "ef2988a6-dff3-4c80-a346-380241a35991"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "JL", "name": "截流", "is_acquired": 1, "acquire_date": "2019-03-30", "is_exist": true}
|
||||
{"_id": "58146e7a-a3b4-4f72-a672-51146c9326ee", "_rev": "3-f15d1ee1cdab34ca2f5116a608df432b", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "8a92f41e-6aea-499a-a14f-3b5f6ab84a15"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "8a92f41e-6aea-499a-a14f-3b5f6ab84a15"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "8a92f41e-6aea-499a-a14f-3b5f6ab84a15"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "JZPC", "name": "机组盘车", "is_acquired": 1, "acquire_date": "2025-07-18", "is_exist": true}
|
||||
{"_id": "5a642ab1-c3d1-41d5-a1ad-271708db3b8b", "_rev": "5-0d49a78cf2f53644170c238fcc57f5a7", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "d15eaeb3-601d-44c9-b891-4604ae5910be"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "d15eaeb3-601d-44c9-b891-4604ae5910be"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "d15eaeb3-601d-44c9-b891-4604ae5910be"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "YSTS", "name": "有水调试", "is_acquired": 1, "acquire_date": "2025-12-05", "is_exist": true}
|
||||
{"_id": "65dcd353-4849-4f88-9568-772a2a1f815a", "_rev": "3-fae1cb2a266ddade84e6ef4b69ede889", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "3bd21a3d-cf7b-4189-99db-71e7c6485868"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "3bd21a3d-cf7b-4189-99db-71e7c6485868"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "3bd21a3d-cf7b-4189-99db-71e7c6485868"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "TZJC", "name": "投资决策", "is_acquired": 1, "acquire_date": "2015-07-31", "is_exist": true}
|
||||
{"_id": "7ccbdd34-1b1c-4e2d-8f2c-e4f1fe1e8338", "_rev": "1-68e66ab5d401802723820f5107be11dd", "field_metadata": null, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "HZBA", "name": "项目核准", "is_acquired": 1, "acquire_date": "2016-11-10", "is_exist": true}
|
||||
{"_id": "8fa18aee-c77d-4780-8976-3277a91b9e2c", "_rev": "3-69e4250f2b009412074546e0cdb60191", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "d7676817-db7d-4d90-a9de-deb140831a9b"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "d7676817-db7d-4d90-a9de-deb140831a9b"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "d7676817-db7d-4d90-a9de-deb140831a9b"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "WSGAZ", "name": "尾水管安装", "is_acquired": 1, "acquire_date": "2023-10-06", "is_exist": true}
|
||||
{"_id": "9086580f-764b-4b87-ae08-5b5751b7d21f", "_rev": "3-8acf6b336446ed9b12ec8c4f95a1e83d", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "0e9bb869-8ea9-4675-b88f-6bd7d986d5d9"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "0e9bb869-8ea9-4675-b88f-6bd7d986d5d9"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "0e9bb869-8ea9-4675-b88f-6bd7d986d5d9"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "DZDZ", "name": "定子吊装", "is_acquired": 1, "acquire_date": "2025-01-01", "is_exist": true}
|
||||
{"_id": "96c20717-7ea4-4396-a24c-34413dc17907", "_rev": "3-a1eefe4baf51cacd4162940d0b698846", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "00134d0c-f6b1-49be-b170-8c58a8865e82"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "00134d0c-f6b1-49be-b170-8c58a8865e82"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "00134d0c-f6b1-49be-b170-8c58a8865e82"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "FDJCJM", "name": "发电机层交面", "is_acquired": 1, "acquire_date": "2024-11-30", "is_exist": true}
|
||||
{"_id": "9ecab2df-25f3-4976-ad61-79fe4ad8f2c3", "_rev": "3-ec2bd330ced3a42d3da3eb811d0746ff", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "b6c9e978-839b-4c0d-912d-3071341b81ce"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "b6c9e978-839b-4c0d-912d-3071341b81ce"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "b6c9e978-839b-4c0d-912d-3071341b81ce"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "JRPF", "name": "接入批复", "is_acquired": 1, "acquire_date": "2022-05-05", "is_exist": true}
|
||||
{"_id": "c144a156-a040-4828-be1b-813c82aaed43", "_rev": "3-d494c5331e8642578494f7606846c875", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "d3607649-eeb6-42dc-b4c7-de0adb80e058"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "d3607649-eeb6-42dc-b4c7-de0adb80e058"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "d3607649-eeb6-42dc-b4c7-de0adb80e058"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "XXYD", "name": "先行用地批复", "is_acquired": 1, "acquire_date": "2016-05-13", "is_exist": true}
|
||||
{"_id": "e181fccc-bc12-4910-8916-bf66837a50d1", "_rev": "3-3ef0a3985c89b318f7a2a6a0d77a48da", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "3e4ad619-b942-4a12-814c-5fa0aeee025d"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "3e4ad619-b942-4a12-814c-5fa0aeee025d"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "3e4ad619-b942-4a12-814c-5fa0aeee025d"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "WKAZ", "name": "蜗壳安装", "is_acquired": 1, "acquire_date": "2024-05-19", "is_exist": true}
|
||||
{"_id": "e745e740-d0d7-4b2a-ba53-9a23d16707a4", "_rev": "3-6d1ecbdd2080a833e9a289c63e2bd8f7", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "d9a65f5c-3639-4901-9d3c-8faf50e950aa"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "d9a65f5c-3639-4901-9d3c-8faf50e950aa"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "d9a65f5c-3639-4901-9d3c-8faf50e950aa"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "XZXS", "name": "下闸蓄水", "is_acquired": 1, "acquire_date": "2025-10-13", "is_exist": true}
|
||||
{"_id": "ecb80c08-55d1-4784-b8fb-7f56368816d9", "_rev": "3-40b93a0ed42af1c04c0a6e451ad24947", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "8402122a-b4ee-4493-91b9-60ee36bf4596"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "8402122a-b4ee-4493-91b9-60ee36bf4596"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "8402122a-b4ee-4493-91b9-60ee36bf4596"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "ZLDZ", "name": "转轮吊装", "is_acquired": 1, "acquire_date": "2025-04-25", "is_exist": true}
|
||||
{"_id": "0121ace1-38d8-4be7-b6af-e197fc6a8d16", "_rev": "3-0ad99926f93322dbb88cdf862148b5da", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "e83af8ff-d4f2-484e-b178-8f8afe2b65bc"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "e83af8ff-d4f2-484e-b178-8f8afe2b65bc"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "e83af8ff-d4f2-484e-b178-8f8afe2b65bc"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "TZJC", "name": "投资决策", "is_acquired": 1, "acquire_date": "2021-07-27", "is_exist": true}
|
||||
{"_id": "06866612-11ba-411d-acb7-5476b891d211", "_rev": "3-40f09c07ef8acb8d80d0dd00b5a544f0", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "3bc7400d-f488-43f9-a05d-82cecc76ec47"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "3bc7400d-f488-43f9-a05d-82cecc76ec47"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "3bc7400d-f488-43f9-a05d-82cecc76ec47"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "ZLJDBA", "name": "质量监督备案", "is_acquired": 1, "acquire_date": "2024-10-16", "is_exist": true}
|
||||
{"_id": "12e7e3e9-ca2d-4457-b89e-ee9e968ce50f", "_rev": "1-7700a8a38cdcaacbffce02a89d2456cd", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "ZLDZ", "name": "转轮吊装", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "13c6c808-66d0-4e04-ad42-2e574f26a6b2", "_rev": "1-b394dfcbb16c21dfba53c32b23691cc1", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "YSTS", "name": "有水调试", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "1cdd3f3c-aa21-417d-8f01-12f9789c9639", "_rev": "1-4a2615bda7d0a946dbd60d9544f3fbd3", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "JZPC", "name": "机组盘车", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "2850ed59-12f0-4aea-85a1-83dfac693217", "_rev": "3-01330a2164140f8d0ba7712cd73d7de4", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "20e02e32-e6e2-4b24-9f9a-edc313c8c158"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "20e02e32-e6e2-4b24-9f9a-edc313c8c158"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "20e02e32-e6e2-4b24-9f9a-edc313c8c158"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "JL", "name": "截流", "is_acquired": 1, "acquire_date": "2025-10-18", "is_exist": true}
|
||||
{"_id": "4925d967-5e9a-4d96-8b2b-275b0a04a86d", "_rev": "1-fcd393c5d29cc67c783c0068c94480c6", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "ZZDZ", "name": "转子吊装", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "6548c93d-114d-4db7-b49b-6835a52d1d12", "_rev": "1-340923b4dd572af3557fcc74aa5eeb12", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "FDJCJM", "name": "发电机层交面", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "736c0863-9f41-4d7b-8678-6b389ad4c5c3", "_rev": "3-6b92ad997d458696807a4288d74dba71", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "2bfad1a1-0be2-4cf2-afe1-2c0a19066c8e"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "2bfad1a1-0be2-4cf2-afe1-2c0a19066c8e"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "2bfad1a1-0be2-4cf2-afe1-2c0a19066c8e"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "HSBPF", "name": "环水保“三同时”批复", "is_acquired": 1, "acquire_date": "2022-09-08", "is_exist": true}
|
||||
{"_id": "8b46a717-20b2-4362-9987-2cf72a4a1c33", "_rev": "1-2113257f7a60a6aa46e862dd2e8a1547", "field_metadata": null, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "HZBA", "name": "项目核准", "is_acquired": 1, "acquire_date": "2023-05-24", "is_exist": true}
|
||||
{"_id": "917be469-77af-467a-b024-b51e89fa0288", "_rev": "1-58e241deda4a654669c596bdd8e99d2c", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "DZDZ", "name": "定子吊装", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "a07d40ca-5b70-4af1-96c8-07e9166a9fdc", "_rev": "3-b94b6c75cadbf4618ad6681e4c89091f", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "ef95601b-e055-49b7-9c74-611d9e2b7ad4"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "ef95601b-e055-49b7-9c74-611d9e2b7ad4"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "ef95601b-e055-49b7-9c74-611d9e2b7ad4"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "XXYD", "name": "先行用地批复", "is_acquired": 1, "acquire_date": "2023-10-27", "is_exist": true}
|
||||
{"_id": "a124d8ae-569f-4136-8555-bef28a0b67e8", "_rev": "3-336f00977a48906236aae16937d61f52", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "5d3251cd-8ceb-434a-8cb4-fb36dd15ccb9"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "5d3251cd-8ceb-434a-8cb4-fb36dd15ccb9"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "5d3251cd-8ceb-434a-8cb4-fb36dd15ccb9"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "KYPF", "name": "可研批复", "is_acquired": 1, "acquire_date": "2023-05-24", "is_exist": true}
|
||||
{"_id": "b20db459-6503-4772-b582-6f1de4fbf7c5", "_rev": "3-e9361752d903e9151f34c08492d8cc16", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "c03de6f4-8853-4e26-a0a3-dc870776a06a"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "c03de6f4-8853-4e26-a0a3-dc870776a06a"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "c03de6f4-8853-4e26-a0a3-dc870776a06a"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "DXCFKW", "name": "地下厂房开挖", "is_acquired": 1, "acquire_date": "2025-05-13", "is_exist": true}
|
||||
{"_id": "b967899b-9796-4e8a-8bb3-a42cb7d2aa5c", "_rev": "1-e9655483f43caf4479bd2c6ab68362f1", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "WSTS", "name": "无水调试", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "c11b357c-f120-469a-ac80-14d07bd597e4", "_rev": "1-99317745e9f5e12afaaf7219459c3179", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "WKAZ", "name": "蜗壳安装", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "c356b242-a3a1-4f2d-9da5-e529e59ce902", "_rev": "3-aadad5c251807da6e7bee5dc19fe5163", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "a7ff64d0-0157-4f9e-9b12-d5f2547c0420"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "a7ff64d0-0157-4f9e-9b12-d5f2547c0420"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "a7ff64d0-0157-4f9e-9b12-d5f2547c0420"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "YDPF", "name": "用地批复", "is_acquired": 1, "acquire_date": "2024-11-04", "is_exist": true}
|
||||
{"_id": "f5b9e719-f8ae-4d3c-bd6b-538c1eac7458", "_rev": "3-1a73e7d641de5ac3edb86baea8fdf7c4", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "5c0bd002-066f-4935-8bdc-eb6fd1172eca"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "5c0bd002-066f-4935-8bdc-eb6fd1172eca"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "5c0bd002-066f-4935-8bdc-eb6fd1172eca"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "JRPF", "name": "接入批复", "is_acquired": 1, "acquire_date": "2022-03-28", "is_exist": true}
|
||||
{"_id": "f5fc7405-6d55-4503-ba86-a1ff90f29f24", "_rev": "3-9e27a56beaa8b4792d0d1680eaa207b6", "field_metadata": {"acquire_date": {"approval_status": "rejected", "approval_flow_id": "909bffa1-e505-4226-9a07-4aa1ca09aab3"}, "is_exist": {"approval_status": "rejected", "approval_flow_id": "909bffa1-e505-4226-9a07-4aa1ca09aab3"}, "is_acquired": {"approval_status": "rejected", "approval_flow_id": "909bffa1-e505-4226-9a07-4aa1ca09aab3"}}, "approval_user": null, "approval_status": "rejected", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "XZXS", "name": "下闸蓄水", "is_acquired": 1, "acquire_date": "2028-12-01", "is_exist": true}
|
||||
{"_id": "fa54c738-626a-41f3-bb76-427ffbe1f9f2", "_rev": "5-713907db5b6a315ee651f3feb174d4f9", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "6b7236f7-78b5-44ea-8d8f-b0e1769aef43"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "6b7236f7-78b5-44ea-8d8f-b0e1769aef43"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "6b7236f7-78b5-44ea-8d8f-b0e1769aef43"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "preparation", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "WSGAZ", "name": "尾水管安装", "is_acquired": 1, "acquire_date": "2029-04-30", "is_exist": true}
|
||||
@@ -0,0 +1,28 @@
|
||||
{"_id": "22af2efe-376e-4924-8286-5416f11f7e37", "_rev": "1-061859da80bcda6be9cf047a864fc0eb", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "JGJS", "name": "竣工决算", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "46a41e77-62d7-46c9-bae6-4c08e1868feb", "_rev": "3-03d64f8de738a4de7d6f60ed74ddf5f7", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "8d24c1e0-34b1-41cd-be0e-557e286c499b"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "8d24c1e0-34b1-41cd-be0e-557e286c499b"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "8d24c1e0-34b1-41cd-be0e-557e286c499b"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "HJBH", "name": "环保验收", "is_acquired": 1, "acquire_date": "2025-08-22", "is_exist": true}
|
||||
{"_id": "7b53b4c1-3451-4aad-8590-d184dd3a3665", "_rev": "3-f7c9625b9c098f1580ed2b479b365f34", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "2c1962c3-b8cf-4dea-bf53-b732a2284875"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "2c1962c3-b8cf-4dea-bf53-b732a2284875"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "2c1962c3-b8cf-4dea-bf53-b732a2284875"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "DAYS", "name": "工程档案验收", "is_acquired": 1, "acquire_date": "2025-12-19", "is_exist": true}
|
||||
{"_id": "871a0319-83c1-4d04-a39d-0f14b639f88b", "_rev": "1-14616eb06f647f706b988ed15d87da30", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "JGYS", "name": "竣工验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "928b6348-8a44-4de7-a8b7-91629dccae58", "_rev": "3-85b6df09d2382e4c450e652038a8f40c", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "f3ef2d27-e231-4bd6-9497-23e0c127a70f"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "f3ef2d27-e231-4bd6-9497-23e0c127a70f"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "f3ef2d27-e231-4bd6-9497-23e0c127a70f"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "SNGC", "name": "枢纽工程验收", "is_acquired": 1, "acquire_date": "2025-09-26", "is_exist": true}
|
||||
{"_id": "9b8bb9c4-6105-4df6-95b7-96be20dac179", "_rev": "1-8aad332ace4ec95ca19cc6b30faf8c25", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "WGJS", "name": "竣工结算", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "a15bed01-9591-45fa-a1a8-66d41da7b762", "_rev": "2-0dd7f83ba1bc9c3b3346ab2d4d426846", "field_metadata": null, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "STTC", "name": "首台投产", "is_acquired": 0, "acquire_date": "2025-12-27", "is_exist": true}
|
||||
{"_id": "aa828021-8a0c-478b-a514-059cc02f63df", "_rev": "1-905ec78252d38b9b39f63189f5555456", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "JGDBTC", "name": "竣工达标投产", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "afb91569-849b-43fb-8724-b6f92aedc8b0", "_rev": "3-8ccc827f3bf9ad9aedb7348b30874d55", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "3d29cca1-9e0b-484b-9dac-a76b87f30500"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "3d29cca1-9e0b-484b-9dac-a76b87f30500"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "3d29cca1-9e0b-484b-9dac-a76b87f30500"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "STBC", "name": "水保验收", "is_acquired": 1, "acquire_date": "2025-08-21", "is_exist": true}
|
||||
{"_id": "b42459d1-b642-40a7-8640-5c59e5c0d131", "_rev": "3-231206f6ec13979c58df24439a9f7a10", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "48e8ed4c-4c7e-426e-95bc-1feff4da3187"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "48e8ed4c-4c7e-426e-95bc-1feff4da3187"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "48e8ed4c-4c7e-426e-95bc-1feff4da3187"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "ZDYM", "name": "征地移民安置验收", "is_acquired": 1, "acquire_date": "2025-05-23", "is_exist": true}
|
||||
{"_id": "b82e653a-9746-446e-bb5c-5b10d8f5e754", "_rev": "3-9dde76a5027e54a1c823c7b8ed9897ec", "field_metadata": {"acquire_date": {"approval_status": "approved", "approval_flow_id": "3a158ce3-15f8-42ea-92dd-d0f5438aa612"}, "is_exist": {"approval_status": "approved", "approval_flow_id": "3a158ce3-15f8-42ea-92dd-d0f5438aa612"}, "is_acquired": {"approval_status": "approved", "approval_flow_id": "3a158ce3-15f8-42ea-92dd-d0f5438aa612"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "XFYS", "name": "消防验收", "is_acquired": 1, "acquire_date": "2025-12-13", "is_exist": true}
|
||||
{"_id": "eb599c3a-4fcc-4adf-b566-dac2c038903a", "_rev": "1-6dd5ef3eb4479ef7c75cd51db4378eaa", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "QBTC", "name": "全部投产", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "f3db07df-823c-4e38-8cf1-35e72e1a4948", "_rev": "1-ba8a62b9738a1625ef5e1b2d66040e27", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 13:26:02", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 13:26:02", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "LAYS", "name": "劳动安全与工业卫生验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "03fbe020-0d31-4446-a13a-c46bf68f51ad", "_rev": "1-b1c2c48eadd0d2bf3da71dc734a52c06", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "QBTC", "name": "全部投产", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "0f957d3d-367a-4f24-a6c8-0be465189335", "_rev": "1-721e5547ab2028b6735f3e41806debf9", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "JGYS", "name": "竣工验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "1994cca9-88eb-4392-8239-d188fced0c97", "_rev": "1-0b8100fd5bb91175d728ce177fe71c3b", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "HJBH", "name": "环保验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "2e979e90-dc05-40fc-8488-cf47716a34b5", "_rev": "1-f61edc8d88ee5673dcfe9229344bd7e0", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "JGJS", "name": "竣工决算", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "30708ded-1c9b-4d31-9722-531bd061e4eb", "_rev": "1-5f3b6d67d9cce4454e558d0298565c91", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "LAYS", "name": "劳动安全与工业卫生验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "45a0440f-ab0f-44c5-a0ae-74134857998f", "_rev": "1-456e32fb69ca985f142bdaa1c48e3795", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "STBC", "name": "水保验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "469da2d6-7511-4cfa-b8ba-5417b370a657", "_rev": "1-ff15a799012a8429f455a589a9c169a0", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "XFYS", "name": "消防验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "8e33dcf6-0465-47dd-b9a0-e31597b87c75", "_rev": "1-f9f72d1ea6d12f5e95fc1c8dd90a5b49", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "SNGC", "name": "枢纽工程验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "9671619f-71b8-486b-9a07-a39f1f988578", "_rev": "1-d56263a60809b9ee0595f2a1a39c6410", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "ZDYM", "name": "征地移民安置验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "c6b70eab-ed63-4992-9c71-cb6809b93cd5", "_rev": "1-01f017f8f4c6f894d709f62f10f8db4a", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "DAYS", "name": "工程档案验收", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "decedc07-4cb4-4ab8-ac78-c718bde5abff", "_rev": "1-5171973e82e9e52a992268afa2936562", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "STTC", "name": "首台投产", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "ed50f8cc-f7b3-4f22-8d7b-8edd8cc8a416", "_rev": "1-6520e53cb906422bdc125d66a24c7e87", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "JGDBTC", "name": "竣工达标投产", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "f52cf38e-13fa-42b7-99a3-d97529bf3f3a", "_rev": "1-49234a871c7a1c7b58a9d449d69fb637", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-07 16:20:49", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-11-07 16:20:49", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "WGJS", "name": "竣工结算", "is_acquired": 0, "acquire_date": null, "is_exist": true}
|
||||
{"_id": "5943fc7b-b2c2-4cbf-ade2-db22fda994bd", "_rev": "1-192e1e46e24e4f46b3d987dd97e965c9", "type": "production", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "code": "CQZS", "name": "产权证书", "acquire_date": null, "is_acquired": 0, "created_at": "2025-11-18 09:18:13", "updated_at": "2025-11-18 09:18:13"}
|
||||
{"_id": "b1edc83f-8a97-4da0-badf-6f867a49b111", "_rev": "1-feda423dd7e357cfcc5958304315b18a", "type": "production", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "code": "CQZS", "name": "产权证书", "acquire_date": null, "is_acquired": 0, "created_at": "2025-11-18 09:18:13", "updated_at": "2025-11-18 09:18:13"}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "_rev": "35-b1812f698ebde74cda680226eab83156", "field_metadata": {"actual_construction_date": {"edit_after_approve": true}, "constructing_capacity": {"approval_status": "approved", "approval_flow_id": "85c9a2a7-cd8a-4e2d-8a78-a303aec82d09", "edit_after_approve": true}, "complete_investment": {"edit_after_approve": true}, "completed_settlement_quantity": {"edit_after_approve": true}, "progress_type": {"edit_after_approve": true}, "key_constraints": {"edit_after_approve": true}, "production_capacity": {"edit_after_approve": true}, "key_constraints_remark": {"edit_after_approve": true}, "completed_investment": {"approval_status": "under_review", "approval_flow_id": "b4b5b9b7-d252-4d1a-8e45-27d3a2e49277", "edit_after_approve": true}, "actual_construction_capacity": {"edit_after_approve": true}, "plan_production_date": {"approval_status": "approved", "approval_flow_id": "d29ac58d-1443-45c0-83db-2b28d0ef4f53"}, "plan_full_production_date": {"approval_status": "approved", "approval_flow_id": "d29ac58d-1443-45c0-83db-2b28d0ef4f53"}, "ensure_production_capacity": {"approval_status": "approved", "approval_flow_id": "84c17edb-69cc-4ff0-9577-5cb305d62b63"}, "climb_production_capacity": {"approval_status": "approved", "approval_flow_id": "e8e2cc05-1c53-480f-8707-06296564d4e4"}, "challenge_production_capacity": {"approval_status": "approved", "approval_flow_id": "7fac41d1-907d-4321-88d7-66721e9f2387"}, "implementation_estimate": {"approval_status": "under_review", "approval_flow_id": "b4b5b9b7-d252-4d1a-8e45-27d3a2e49277"}, "static_total_investment": {"approval_status": "under_review", "approval_flow_id": "b4b5b9b7-d252-4d1a-8e45-27d3a2e49277"}, "dynamic_investment": {"approval_status": "under_review", "approval_flow_id": "b4b5b9b7-d252-4d1a-8e45-27d3a2e49277"}}, "approval_user": "a775915a-0bed-4a17-94f0-47b29916be90", "approval_status": "approved", "approval_comment": "审核通过", "approval_time": "2025-11-07 13:26:01", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-26 10:25:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project", "address": "中国四川省甘孜藏族自治州白玉县", "code": "", "name": "某某水电站", "short_name": "", "region_name": ["中国", "四川省", "甘孜藏族自治州", "白玉县"], "region_path": ["100000", "510000", "513300", "513331"], "province": "510000", "is_domestic": true, "company_id": "a1d69bf1-b95e-4832-9258-5bc35c629e9a", "company_name": "金上公司", "manager_name": "夏勇", "manager_phone": "18328050943", "project_type": "hydropower", "authorization_date": "2016-11-10", "authorized_capacity": 224.0, "investment_decision_capacity": 228.5, "investment_decision_date": "2015-07-31", "plan_construction_capacity": 0.0, "plan_construction_date": "", "actual_construction_capacity": 0.0, "actual_construction_date": "", "accumulated_construction_capacity": 224.0, "constructing_capacity": 122.0, "dynamic_investment": 3335700.0, "complete_investment": 0.0, "ensure_production_capacity": 20, "challenge_production_capacity": 20, "climb_production_capacity": 20, "plan_production_date": "2025-12-31", "plan_full_production_date": "2026-05-31", "production_capacity": 0.0, "production_date": "", "total_production_capacity": 102.0, "actual_production_date": "2025-12-27", "actual_full_production_date": null, "progress_type": "C", "key_constraints": "NONE", "key_constraints_remark": "", "status": "partially_connected", "apply_file_ids": ["eb2b8b49d0b14318b1b7e9ffbccfc388"], "syxs": null, "sub_type": null, "dbtc_score_list": [], "scgc_type": "power", "dam_type": "GB", "storage_capacity": 108000.0, "normal_storage_level": 2894.0, "regulation_performance": "NTJ", "workshop_type": "DX", "precon_start_date": "2017-06", "precon_end_date": "2019-03", "maincon_start_date": "2019-03", "maincon_end_date": "2025-12", "comm_start_date": "2025-12", "comm_end_date": "2026-12", "implementation_estimate": 2746700.0, "static_total_investment": 2565200.0, "completed_investment": 1926600.0, "total_contract_quantity": 1271.0, "completed_settlement_quantity": null, "first_actual_construction_date": "2019-03-30"}
|
||||
{"_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "_rev": "20-7448552b6b9fb5ca20688049150ae037", "field_metadata": {"actual_construction_date": {"edit_after_approve": true}, "constructing_capacity": {"edit_after_approve": true}, "complete_investment": {"edit_after_approve": true}, "completed_settlement_quantity": {"edit_after_approve": true}, "progress_type": {"edit_after_approve": true}, "key_constraints": {"edit_after_approve": true}, "production_capacity": {"edit_after_approve": true}, "key_constraints_remark": {"edit_after_approve": true}, "completed_investment": {"approval_status": "under_review", "approval_flow_id": "d5feb908-6628-484e-ac3f-b2f505f56199", "edit_after_approve": true}, "actual_construction_capacity": {"edit_after_approve": true}, "static_total_investment": {"approval_status": "under_review", "approval_flow_id": "d5feb908-6628-484e-ac3f-b2f505f56199"}, "dynamic_investment": {"approval_status": "under_review", "approval_flow_id": "d5feb908-6628-484e-ac3f-b2f505f56199"}}, "approval_user": "a775915a-0bed-4a17-94f0-47b29916be90", "approval_status": "approved", "approval_comment": "审核通过", "approval_time": "2025-11-07 16:20:49", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 14:58:45", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2026-02-26 09:07:18", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project", "address": "中国西藏自治区昌都市芒康县", "code": "", "name": "某某水电站2", "short_name": "", "region_name": ["中国", "西藏自治区", "昌都市", "芒康县"], "region_path": ["100000", "540000", "540300", "540328"], "province": "540000", "is_domestic": true, "company_id": "a1d69bf1-b95e-4832-9258-5bc35c629e9a", "company_name": "金上公司", "manager_name": "杜光远", "manager_phone": "13551034084", "project_type": "hydropower", "authorization_date": "2023-05-24", "authorized_capacity": 82.6, "investment_decision_capacity": 82.6, "investment_decision_date": "2021-07-27", "plan_construction_capacity": 0.0, "plan_construction_date": "", "actual_construction_capacity": 0.0, "actual_construction_date": "", "accumulated_construction_capacity": 82.6, "constructing_capacity": 82.6, "dynamic_investment": 1412584.9, "complete_investment": 0.0, "ensure_production_capacity": 0.0, "challenge_production_capacity": 0.0, "climb_production_capacity": 0.0, "plan_production_date": null, "plan_full_production_date": null, "production_capacity": 0.0, "production_date": "", "total_production_capacity": 0.0, "actual_production_date": null, "actual_full_production_date": null, "progress_type": "C", "key_constraints": "NONE", "key_constraints_remark": "", "status": "started", "apply_file_ids": ["095a2434910a42deb154cf8b0dc7b47c"], "syxs": null, "sub_type": null, "dbtc_score_list": [], "scgc_type": "power", "dam_type": "ZLB", "storage_capacity": 1670.0, "normal_storage_level": 2387.0, "regulation_performance": "RTJ", "workshop_type": "DX", "precon_start_date": "2023-05", "precon_end_date": "2025-03", "maincon_start_date": "2025-04", "maincon_end_date": "2030-05", "comm_start_date": "2030-06", "comm_end_date": "2031-12", "implementation_estimate": null, "static_total_investment": 1224284.97, "completed_investment": 194269.0, "total_contract_quantity": null, "completed_settlement_quantity": null, "first_actual_construction_date": "2023-09-25"}
|
||||
@@ -0,0 +1,8 @@
|
||||
{"_id": "9df493ae-2a57-4b80-bad4-9728e4f20afd", "_rev": "3-59745295d766dc4da7be4cc7ac805f0b", "field_metadata": {"value": {"approval_status": "approved", "approval_flow_id": "84c17edb-69cc-4ff0-9577-5cb305d62b63", "edit_after_approve": true}, "project_id": {"approval_status": "approved", "approval_flow_id": "84c17edb-69cc-4ff0-9577-5cb305d62b63"}, "key": {"approval_status": "approved", "approval_flow_id": "84c17edb-69cc-4ff0-9577-5cb305d62b63"}, "type": {"approval_status": "approved", "approval_flow_id": "84c17edb-69cc-4ff0-9577-5cb305d62b63"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-10 09:12:11", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-26 10:25:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project_detail_data", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "key": "ensure_production", "value": [{"year": 2025, "capacity": 51.0, "is_audit": true}, {"year": 2026, "capacity": 20, "is_audit": true}]}
|
||||
{"_id": "9a58e4c5-4926-4cd5-b54a-8d78bda3c237", "_rev": "3-e239459aed74b56722488b0749f00add", "field_metadata": {"value": {"approval_status": "approved", "approval_flow_id": "e8e2cc05-1c53-480f-8707-06296564d4e4", "edit_after_approve": true}, "project_id": {"approval_status": "approved", "approval_flow_id": "e8e2cc05-1c53-480f-8707-06296564d4e4"}, "key": {"approval_status": "approved", "approval_flow_id": "e8e2cc05-1c53-480f-8707-06296564d4e4"}, "type": {"approval_status": "approved", "approval_flow_id": "e8e2cc05-1c53-480f-8707-06296564d4e4"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-10 09:12:16", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-26 10:25:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project_detail_data", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "key": "climb_production", "value": [{"year": 2025, "capacity": 102.0, "is_audit": true}, {"year": 2026, "capacity": 20, "is_audit": true}]}
|
||||
{"_id": "c3d3bff4-6591-4b71-b4c9-fb62697ba7ec", "_rev": "3-207e7ac49468d6a628c39bb7dd9b8b5d", "field_metadata": {"value": {"approval_status": "approved", "approval_flow_id": "7fac41d1-907d-4321-88d7-66721e9f2387", "edit_after_approve": true}, "project_id": {"approval_status": "approved", "approval_flow_id": "7fac41d1-907d-4321-88d7-66721e9f2387"}, "key": {"approval_status": "approved", "approval_flow_id": "7fac41d1-907d-4321-88d7-66721e9f2387"}, "type": {"approval_status": "approved", "approval_flow_id": "7fac41d1-907d-4321-88d7-66721e9f2387"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-10 09:12:21", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2026-02-26 10:25:28", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project_detail_data", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "key": "challenge_production", "value": [{"year": 2025, "capacity": 102.0, "is_audit": true}, {"year": 2026, "capacity": 20, "is_audit": true}]}
|
||||
{"_id": "90d66bbb-6934-42ca-b8f8-f6ffb226447a", "_rev": "2-c069e6a12f364c008deb4a27505ed95f", "field_metadata": {"value": {"approval_status": "approved", "approval_flow_id": "a1859f8e-27a7-4af7-9b30-9cf3fc3633e2", "edit_after_approve": true}, "project_id": {"approval_status": "approved", "approval_flow_id": "a1859f8e-27a7-4af7-9b30-9cf3fc3633e2"}, "key": {"approval_status": "approved", "approval_flow_id": "a1859f8e-27a7-4af7-9b30-9cf3fc3633e2"}, "type": {"approval_status": "approved", "approval_flow_id": "a1859f8e-27a7-4af7-9b30-9cf3fc3633e2"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": "2025-12-29 14:46:50", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-18 15:55:15", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-18 15:55:15", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project_detail_data", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "key": "actual_construction", "value": [{"year": 2019, "date": "2019-03-30", "capacity": 224.0, "is_audit": true}]}
|
||||
{"_id": "990ad5c2-a083-4166-b6b0-be4ae5ca7e06", "_rev": "2-220bc59abb0e8082ff84e6c7c988eda8", "field_metadata": {"value": {"approval_status": "approved", "approval_flow_id": "dc8eb158-3ad0-486c-a2ef-bc47cbf3b246", "edit_after_approve": true}, "project_id": {"approval_status": "approved", "approval_flow_id": "dc8eb158-3ad0-486c-a2ef-bc47cbf3b246"}, "key": {"approval_status": "approved", "approval_flow_id": "dc8eb158-3ad0-486c-a2ef-bc47cbf3b246"}, "type": {"approval_status": "approved", "approval_flow_id": "dc8eb158-3ad0-486c-a2ef-bc47cbf3b246"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": "2025-12-29 14:46:47", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-18 15:56:10", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-11-18 15:56:10", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project_detail_data", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "key": "plan_construction", "value": [{"year": 2018, "date": "2018-11-01", "capacity": 224.0, "is_audit": true}]}
|
||||
{"_id": "0b3f7e2d-9dc7-4f71-aac9-c9e7093df64f", "_rev": "1-d70398cf5d8fc88652e0c6d16b14c15b", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "value": [], "type": "project_detail_data", "approval_status": "approved", "key": "production", "created_at": "2025-11-19 13:15:44", "updated_at": "2025-11-19 13:15:44"}
|
||||
{"_id": "b080f519-e313-445a-b22e-1039e41e93bb", "_rev": "3-800285f785d3b8d1ffb50ea18dfd0e59", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "value": [{"year": 2025, "date": "2025-12-27", "capacity": 51.0, "is_audit": true}, {"year": 2025, "date": "2025-12-28", "capacity": 51.0, "is_audit": true}], "type": "project_detail_data", "approval_status": "approved", "key": "production", "created_at": "2025-11-19 13:15:44", "updated_at": "2025-11-19 13:15:44"}
|
||||
{"_id": "c99ae2e4-809e-47dd-8b86-61674b6a5bea", "_rev": "2-ab2b7cfb8cb68378fa5ddbf01bb5a6c1", "field_metadata": {"value": {"approval_status": "approved", "approval_flow_id": "22211c56-137a-48f4-921d-6a9f781ce74f", "edit_after_approve": true}, "project_id": {"approval_status": "approved", "approval_flow_id": "22211c56-137a-48f4-921d-6a9f781ce74f"}, "key": {"approval_status": "approved", "approval_flow_id": "22211c56-137a-48f4-921d-6a9f781ce74f"}, "type": {"approval_status": "approved", "approval_flow_id": "22211c56-137a-48f4-921d-6a9f781ce74f"}}, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": "2025-12-09 23:04:40", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-12-05 17:36:01", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-05 17:36:01", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "project_detail_data", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "key": "actual_construction", "value": [{"year": 2023, "date": "2023-09-25", "capacity": 82.6, "is_audit": true}]}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
{"_id": "0798431d-115a-4b1c-b95a-78470160fa9e", "_rev": "3-18cce2b2f9854c79aeb4329c31e6028c", "type": "supplier", "name": "沈阳中变电气有限责任公司", "short_name": "沈阳中变电气有限责任公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "210000", "city": "210100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91210100564677033W", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "210000", "210100"]}
|
||||
{"_id": "1098875c-e949-47b1-9f40-237eb507f890", "_rev": "3-0ef325ac17b9232224f5c9f924e2cf6f", "type": "supplier", "name": "中国水利水电第九工程局有限公司", "short_name": "中国水利水电第九工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "520000", "city": "520100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91520000214428387H", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "520000", "520100"]}
|
||||
{"_id": "1115a7f3-b2c1-4bfb-8c89-605250c402dd", "_rev": "3-6e0a5e272f35cd473d6cd82a1ad6cfa3", "type": "supplier", "name": "中国安能集团第三工程局有限公司", "short_name": "中国安能集团第三工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "915101006331302278", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "1ff5b102-2f9e-496c-8591-1a8e32407c7f", "_rev": "3-2857c4610fd9e9a9b8313dee83454969", "type": "supplier", "name": "中国葛洲坝集团三峡建设工程有限公司", "short_name": "中国葛洲坝集团三峡建设工程有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "420000", "city": "420500", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91420000615573462P", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "420000", "420500"]}
|
||||
{"_id": "4be9e1da-9ebf-4a2a-b6bd-14a41ac31858", "_rev": "5-b54a288a89b9e55cee26d42b08bb69a0", "type": "supplier", "name": "中国水利水电第七工程局有限公司", "short_name": "中国水利水电第七工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91510000201827469M", "created_at": "2025-09-25 20:09:02", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "357c7eaf-5a33-4999-be94-79c42bfbd955", "_rev": "3-35879fa40a8fbe379f03c7a4fa8696ad", "type": "supplier", "name": "广州擎天实业有限公司", "short_name": "广州擎天实业有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "440300", "city": "440100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91440101231240749H", "created_at": "2025-09-25 20:10:42", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "440000", "440100"]}
|
||||
{"_id": "2ca09c22-68b4-4e43-b9fa-619dcda5f325", "_rev": "3-ac12e05cedcda85821240a9066aa91ef", "type": "supplier", "name": "江苏苏博特新材料股份有限公司", "short_name": "江苏苏博特新材料股份有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "320000", "city": "320100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91320000768299302G", "created_at": "2025-09-25 20:10:43", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "320000", "320100"]}
|
||||
{"_id": "31b6b6d7-989b-4abe-a7e1-6d518f3a4020", "_rev": "3-bedf089583a4645867c7036dba8e7a9e", "type": "supplier", "name": "中国水利水电第十工程局有限公司", "short_name": "中国水利水电第十工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "9151018120276341XK", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "34db820f-860c-4c6e-9326-5c7cb385bf50", "_rev": "3-e475374124da6df3a40f38043efb7237", "type": "supplier", "name": "特变电工中发上海高压开关有限公司", "short_name": "特变电工中发上海高压开关有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "310000", "city": "310000", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "9131012078784664XA", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "310000", "310000"]}
|
||||
{"_id": "4b069ce4-3687-4263-a1f2-4735c22c3f8e", "_rev": "3-9cccdfa9f992ae4f0ec07068c479487c", "type": "supplier", "name": "四川二滩国际工程咨询有限责任公司", "short_name": "四川二滩国际工程咨询有限责任公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91510115201873799G", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "2e465bd8-b240-4046-bf00-187d22823f7b", "_rev": "3-2629f9e1646b7e398fd8bb41a7fc47a2", "type": "supplier", "name": "哈尔滨电机厂有限责任公司", "short_name": "哈尔滨电机厂有限责任公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "230000", "city": "230100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "912301991270479655", "created_at": "2025-09-26 17:00:05", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "230000", "230100"]}
|
||||
{"_id": "3ab47229-6da8-4efb-aa44-b96866a2ce13", "_rev": "3-998c447f59be1475e690d1416384fb64", "type": "supplier", "name": "四川蜀府贸易有限公司", "short_name": "四川蜀府贸易有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "915100005632853965", "created_at": "2025-09-26 17:00:10", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "48a5f1a7-5d5e-41cf-8676-042f1d5316f1", "_rev": "2-d43e58afff0c5317401a22d075866c56", "field_metadata": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-27 11:32:41", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-12-25 08:59:53", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "supplier", "code": "czyy", "company_type": "other", "name": "常州液压成套设备厂有限公司", "short_name": "常州液压", "parent_id": null, "path": [], "path_name": [], "province": "320000", "city": "320400", "sort": 0, "status": "active", "company_nature": ["supplier"], "credit_code": "91320412250851852D", "country": "100000", "region_path": ["100000", "320000", "320400"]}
|
||||
{"_id": "67fa779d-2ce9-468f-b94f-a3d29f1f22c9", "_rev": "3-2c6e66d316216cfc460662bf4a40e612", "type": "supplier", "name": "杭州华新机电工程有限公司", "short_name": "杭州华新机电工程有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "330000", "city": "330100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "913301087227885306", "created_at": "2025-09-25 20:10:42", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "330000", "330100"]}
|
||||
{"_id": "594a09af-8944-476d-b098-7aebe96ad4e8", "_rev": "3-fc6edc3d3384c95def0be02ee734a5b2", "type": "supplier", "name": "云南水电十四局东华建筑工程有限公司", "short_name": "云南水电十四局东华建筑工程有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "530000", "city": "530100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91530000713408946K", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "530000", "530100"]}
|
||||
{"_id": "6db1ed5b-f52a-4142-867c-d8b2731ead71", "_rev": "3-f769878777781eb98071dddc7c7c4968", "type": "supplier", "name": "中国水利水电第十四工程局有限公司", "short_name": "中国水利水电第十四工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "530000", "city": "530100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91530100216579074C", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "530000", "530100"]}
|
||||
{"_id": "538e01cd-85cb-42b3-b313-16977f7a5224", "_rev": "3-d9acfbf91ba6d83dc33c94b84127f2e3", "type": "supplier", "name": "中国水利水电第五工程局有限公司", "short_name": "中国水利水电第五工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91510000205804264E", "created_at": "2025-09-26 17:00:12", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "97be34dc-0a17-4ce5-baea-0f3ceee61103", "_rev": "4-4fbf33c81fff4a4a93ba8da7f99b786d", "type": "supplier", "name": "国电南京自动化股份有限公司", "short_name": "国电南京自动化股份有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "320000", "city": "320100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "913201007162522468", "created_at": "2025-09-25 20:09:02", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "320000", "320100"]}
|
||||
{"_id": "77316fb4-6167-432b-94e5-89c3d8a6b900", "_rev": "3-2112fbd151033d97a2c90123a02c70a3", "type": "supplier", "name": "中国水利水电夹江水工机械有限公司", "short_name": "中国水利水电夹江水工机械有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "511100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91511126207500117U", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "511100"]}
|
||||
{"_id": "936c6316-8d87-4681-a3b5-b90ed4804a06", "_rev": "3-a9a9b85f9cdd45dc3646e66c9a1a41aa", "type": "supplier", "name": "中国电建集团成都勘测设计研究院有限公司", "short_name": "中国电建集团成都勘测设计研究院有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "915100004507513971", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "510000", "510100"]}
|
||||
{"_id": "98892419-6a71-4d7e-a0ac-ad5a0a15f1d6", "_rev": "3-f5bb2f9abe284037054df3b323f2482f", "type": "supplier", "name": "中国电建集团贵阳勘测设计研究院有限公司", "short_name": "中国电建集团贵阳勘测设计研究院有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "520000", "city": "520100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "9152000070966703X2", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "520000", "520100"]}
|
||||
{"_id": "9c80aace-ba73-4550-8fef-3080b51027d9", "_rev": "3-0dddd7f05fccce78e17fdf4ae9975f0a", "type": "supplier", "name": "中国水利水电第四工程局有限公司", "short_name": "中国水利水电第四工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "630000", "city": "630100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "9163000022658124XK", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:53", "country": "100000", "region_path": ["100000", "630000", "630100"]}
|
||||
{"_id": "930dfaf9-708e-4ec0-95f4-521b10bf1c00", "_rev": "2-5c464399a48505836497072601a60159", "field_metadata": null, "created_by": "a775915a-0bed-4a17-94f0-47b29916be90", "created_by_name": "集团公司管理员", "created_at": "2025-11-27 11:33:18", "updated_by": "a775915a-0bed-4a17-94f0-47b29916be90", "updated_by_name": "集团公司管理员", "updated_at": "2025-12-25 08:59:53", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "supplier", "code": "hnwz", "company_type": "other", "name": "某公司海南物资有限公司", "short_name": "海南物资", "parent_id": null, "path": [], "path_name": [], "province": "460000", "city": "460100", "sort": 0, "status": "active", "company_nature": ["supplier"], "credit_code": "91469007MA5TW", "country": "100000", "region_path": ["100000", "460000", "460100"]}
|
||||
{"_id": "ab5ab605-f27a-461b-9a88-73d1eafde5ed", "_rev": "3-a463c974fbcb84a524d1ee6ed72e64ec", "type": "supplier", "name": "东方电气集团东方电机有限公司", "short_name": "东方电气集团东方电机有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "510600", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91510600671415848H", "created_at": "2025-09-25 20:10:42", "updated_at": "2025-12-25 08:59:54", "country": "100000", "region_path": ["100000", "510000", "510600"]}
|
||||
{"_id": "b4656ed6-5329-4673-93c8-d11e15d6ece5", "_rev": "3-0a11b989849efb63378b8a8fddb989e4", "type": "supplier", "name": "中国水利水电建设工程咨询西北有限公司", "short_name": "中国水利水电建设工程咨询西北有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "610000", "city": "610100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91610000220530812K", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:54", "country": "100000", "region_path": ["100000", "610000", "610100"]}
|
||||
{"_id": "e0ceec90-0ad7-417f-a669-fd4f5db07eff", "_rev": "4-71df8660a58c5628bb55f2d39a9264fb", "type": "supplier", "name": "西安西电变压器有限责任公司", "short_name": "西安西电变压器有限责任公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "610000", "city": "610100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91610104220601553B", "created_at": "2025-09-25 20:09:02", "updated_at": "2025-12-25 08:59:54", "country": "100000", "region_path": ["100000", "610000", "610100"]}
|
||||
{"_id": "cd9e9224-a08f-4bed-81a6-b289b74506e8", "_rev": "3-572570411c03424fb3370e74b2f7f496", "type": "supplier", "name": "乐山一拉得电网自动化有限公司", "short_name": "乐山一拉得电网自动化有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "510000", "city": "511100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "91511100MA6281NC0N", "created_at": "2025-09-25 20:10:43", "updated_at": "2025-12-25 08:59:54", "country": "100000", "region_path": ["100000", "510000", "511100"]}
|
||||
{"_id": "e88c8c18-bc49-4bab-acc5-6fb78f4c7f8f", "_rev": "3-269fcaf6630593cb44ee3e6a1ffd4ef9", "type": "supplier", "name": "中国水利水电第六工程局有限公司", "short_name": "中国水利水电第六工程局有限公司", "code": "010A", "company_type": "other", "parent_id": "", "path": [], "path_name": [], "province": "210000", "city": "210100", "status": "active", "sort": 2, "created_by": "system", "created_by_name": "system", "updated_by": "system", "updated_by_name": "system", "company_nature": ["construction", "design", "supervisory", "supplier", "goverment"], "credit_code": "9121011211756300XA", "created_at": "2025-09-25 20:10:47", "updated_at": "2025-12-25 08:59:54", "country": "100000", "region_path": ["100000", "210000", "210100"]}
|
||||
@@ -0,0 +1,12 @@
|
||||
{"_id": "142941ac-d308-4bbf-a018-33541c29b360", "_rev": "2-1a05c2005f7ee7991a273ed2d1862de8", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "capacity": 20.0, "plan_production_date": "2026-12-31", "actual_production_date": null, "serial_number": 6}
|
||||
{"_id": "22a3ed8d-6ab4-4e03-83c7-0e8d5a4f54ab", "_rev": "3-9dc5bcb654f0769e93a138efd4d8d088", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "capacity": 51, "plan_production_date": "2026-10-31", "actual_production_date": null, "serial_number": 2}
|
||||
{"_id": "3855f7df-3f6e-42cb-8ce5-d565b213c67c", "_rev": "5-2e4f28a89a06ff33c9b2ee6720d8d26f", "field_metadata": null, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": "2025-12-29 14:40:32", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "capacity": 51, "plan_production_date": "2025-12-31", "actual_production_date": "2025-12-28", "serial_number": 3}
|
||||
{"_id": "858e91ef-14b7-446d-9c60-906387add673", "_rev": "3-ede7292def387a5851bb2643c3e71f6b", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "capacity": 51, "plan_production_date": "2026-08-31", "actual_production_date": null, "serial_number": 1}
|
||||
{"_id": "a7cfff2e-cf35-4199-a0db-e1fd14c583ea", "_rev": "3-d944e815d4786b365cef0e81bfb6b0ff", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "capacity": 20, "plan_production_date": "2026-06-30", "actual_production_date": null, "serial_number": 5}
|
||||
{"_id": "f2a8c85c-e004-4228-92a0-acc90c24c405", "_rev": "5-03d079e59eddafe6484073c789427e62", "field_metadata": null, "approval_user": null, "approval_status": "approved", "approval_comment": null, "approval_time": "2025-12-29 14:40:28", "created_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "created_by_name": "杜晓凡", "created_at": "2025-11-07 12:39:48", "updated_by": "228fd0a5-9cbb-4a2d-bafa-78e892dd13de", "updated_by_name": "杜晓凡", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "0f9c3e22-f4bb-4803-825a-4f238eeb06d5", "capacity": 51, "plan_production_date": "2025-12-31", "actual_production_date": "2025-12-27", "serial_number": 4}
|
||||
{"_id": "05bdc3b1-f455-4182-a50f-39ddfb3f5a69", "_rev": "5-18956223e99169a529aed64e740cbce2", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": "2025-11-21 15:19:32", "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 15:43:32", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "capacity": 4.3, "plan_production_date": "2028-12-31", "actual_production_date": null, "serial_number": 1}
|
||||
{"_id": "82f77395-fcce-4588-bf80-02f245dd4d2c", "_rev": "2-9abd0819e349b5dea12c1fe46471bddf", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 15:43:32", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "capacity": 4.3, "plan_production_date": "2028-12-31", "actual_production_date": null, "serial_number": 2}
|
||||
{"_id": "a1553e0b-84f4-4c67-8f8a-acabd0bef652", "_rev": "2-5ec3a56c4939acb3cf164c71e9c20142", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 15:43:32", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "capacity": 18.5, "plan_production_date": "2030-01-31", "actual_production_date": null, "serial_number": 3}
|
||||
{"_id": "ade9b160-95d9-4304-a25e-b6a68416c809", "_rev": "2-074fd643919358315ffc5902d1b6af2c", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 15:43:32", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "capacity": 18.5, "plan_production_date": "2030-05-31", "actual_production_date": null, "serial_number": 5}
|
||||
{"_id": "e249e37c-5482-4967-8c80-dda9e141abee", "_rev": "2-d290135b54465071145eb64c4fc5eb27", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 15:43:32", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "capacity": 18.5, "plan_production_date": "2030-05-31", "actual_production_date": null, "serial_number": 6}
|
||||
{"_id": "f4b21193-0744-467f-8726-18956515047e", "_rev": "2-5cba3739980d5849b3c324ebbc0190c9", "field_metadata": null, "approval_user": null, "approval_status": null, "approval_comment": null, "approval_time": null, "created_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "created_by_name": "李远运", "created_at": "2025-11-07 15:43:32", "updated_by": "118573d7-2eaf-44f8-9cd7-26c2832229b3", "updated_by_name": "李远运", "updated_at": "2025-12-17 10:22:29", "deleted_at": null, "deleted_by": null, "deleted_by_name": null, "type": "generator_unit", "project_id": "f3e02e84-e81c-4aa6-88d4-f5aa108c8227", "capacity": 18.5, "plan_production_date": "2030-01-31", "actual_production_date": null, "serial_number": 4}
|
||||
@@ -0,0 +1,41 @@
|
||||
[project]
|
||||
name = "ecm-sync-system"
|
||||
version = "0.1.0"
|
||||
description = "ECM sync state machine and pipeline"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"pydantic>=2.7,<3",
|
||||
"email-validator>=2.2,<3",
|
||||
"PyYAML>=6.0,<7",
|
||||
"httpx>=0.27,<1",
|
||||
"aiosqlite>=0.20,<1",
|
||||
"pytz>=2024.1,<2027",
|
||||
"fastapi>=0.115,<1",
|
||||
"uvicorn>=0.30,<1",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
ecm-sync-run = "sync_state_machine.cli:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=8.2,<9",
|
||||
"pytest-asyncio>=0.23,<1",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=69", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools]
|
||||
include-package-data = true
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["sync_state_machine*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
sync_state_machine = ["config/*.yaml"]
|
||||
|
||||
[tool.uv]
|
||||
package = true
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
[pytest]
|
||||
testpaths = tests
|
||||
# 忽略第三方库的弃用警告
|
||||
filterwarnings =
|
||||
ignore::PendingDeprecationWarning:starlette.*
|
||||
# Python 3.14: pytest-asyncio 0.26.0 内部使用已弃用的 asyncio API
|
||||
# 上游 issue: https://github.com/pytest-dev/pytest-asyncio/issues/706
|
||||
# 待 pytest-asyncio 修复后可移除以下两条过滤
|
||||
ignore:'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16:DeprecationWarning:pytest_asyncio\.plugin
|
||||
ignore:'asyncio.set_event_loop_policy' is deprecated and slated for removal in Python 3.16:DeprecationWarning:pytest_asyncio\.plugin
|
||||
# 也可以设置异步测试的默认 loop scope
|
||||
asyncio_default_fixture_loop_scope = function
|
||||
addopts = --ignore=scripts/test_api_sync.py --ignore=scripts/test_api_sync_top10.py --ignore=scripts/test_api_write_real_sample.py
|
||||
@@ -0,0 +1,64 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from sync_state_machine.config import load_overrides_from_file
|
||||
from sync_state_machine.pipeline import build_config, run_pipeline_from_config
|
||||
|
||||
|
||||
def _resolve_config_path(raw_path: str) -> Path:
|
||||
path = Path(raw_path)
|
||||
if not path.is_absolute():
|
||||
path = PROJECT_ROOT / path
|
||||
return path.resolve()
|
||||
|
||||
|
||||
async def _main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Run sync pipeline from config override file")
|
||||
parser.add_argument(
|
||||
"--config_path",
|
||||
required=True,
|
||||
help="Path to run profile file (JSON/YAML, supports relative path, e.g. run_profiles/jsonl_to_jsonl.local.json)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
cfg_path = _resolve_config_path(args.config_path)
|
||||
if not cfg_path.exists() or not cfg_path.is_file():
|
||||
raise FileNotFoundError(f"Config file not found: {cfg_path}")
|
||||
|
||||
overrides = load_overrides_from_file(cfg_path, PROJECT_ROOT)
|
||||
config = build_config(project_root=PROJECT_ROOT, overrides=overrides)
|
||||
|
||||
mode = f"{config.local_datasource.type}->{config.remote_datasource.type}"
|
||||
print(f"🧩 Loaded config file: {cfg_path}")
|
||||
await run_pipeline_from_config(
|
||||
config,
|
||||
title=f"sync_state_machine pipeline ({mode})",
|
||||
print_summary=True,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
try:
|
||||
return asyncio.run(_main())
|
||||
except KeyboardInterrupt:
|
||||
print("\n⚠️ Interrupted by user")
|
||||
return 130
|
||||
except Exception as exc:
|
||||
print(f"\n❌ Pipeline failed: {type(exc).__name__}: {exc}")
|
||||
return 1
|
||||
finally:
|
||||
logging.shutdown()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,18 @@
|
||||
# Run Profiles
|
||||
|
||||
- 路径:项目根目录 `run_profiles/`
|
||||
- 命名:建议使用 `*.local.yaml`(该目录下 YAML 默认会被 git 忽略)
|
||||
|
||||
模板来源:
|
||||
- `run_profiles/preset/jsonl_to_jsonl.default.yaml`
|
||||
- `run_profiles/preset/jsonl_to_api.default.yaml`
|
||||
|
||||
推荐流程:
|
||||
1. 从模板复制到本目录,例如:
|
||||
- `run_profiles/jsonl_to_jsonl.local.yaml`
|
||||
- `run_profiles/jsonl_to_api.local.yaml`
|
||||
2. 按需修改后运行:
|
||||
- `python run.py --config_path=run_profiles/jsonl_to_jsonl.local.yaml`
|
||||
|
||||
支持占位符:
|
||||
- `${PROJECT_ROOT}`:运行时替换为项目根目录绝对路径。
|
||||
@@ -0,0 +1,18 @@
|
||||
# Preset Templates
|
||||
|
||||
该目录存放版本管理的运行配置模板(default)。
|
||||
|
||||
当前模板:
|
||||
- `jsonl_to_jsonl.default.yaml`
|
||||
- `jsonl_to_api.default.yaml`
|
||||
|
||||
使用方式:
|
||||
1. 复制模板到项目根目录 `run_profiles/`,并重命名为你自己的文件(如 `*.local.yaml`)。
|
||||
2. 修改后通过入口运行:
|
||||
- `python run.py --config_path=run_profiles/jsonl_to_jsonl.local.yaml`
|
||||
|
||||
说明:
|
||||
- `run_profiles/*.yaml` / `run_profiles/*.yml` 默认被 `.gitignore` 忽略,用于本地私有配置。
|
||||
- 模板内可使用 `${PROJECT_ROOT}` 占位符。
|
||||
- 模板已显式展开 datasource 与 strategies 关键字段,便于集中审查。
|
||||
- API 数据源支持全局限流配置:`api_rate_limit_max_requests` 与 `api_rate_limit_window_seconds`。
|
||||
@@ -0,0 +1,290 @@
|
||||
node_types:
|
||||
- company
|
||||
- supplier
|
||||
- project
|
||||
- contract
|
||||
- contract_change
|
||||
- construction_task
|
||||
- construction_task_detail
|
||||
- material
|
||||
- material_detail
|
||||
- contract_settlement
|
||||
- contract_settlement_detail
|
||||
- personnel
|
||||
- personnel_detail
|
||||
- preparation
|
||||
- production
|
||||
- lar
|
||||
- lar_change
|
||||
- project_detail_data
|
||||
- units
|
||||
local_datasource:
|
||||
type: jsonl
|
||||
jsonl_dir: ${PROJECT_ROOT}/filtered_datasource/datasource/filtered
|
||||
read_only: false
|
||||
target_project_ids:
|
||||
- "0f9c3e22-f4bb-4803-825a-4f238eeb06d5"
|
||||
- "f3e02e84-e81c-4aa6-88d4-f5aa108c8227"
|
||||
handler_configs: {}
|
||||
remote_datasource:
|
||||
type: api
|
||||
api_base_url: http://localhost:8000/api/third/v2
|
||||
api_uid: 6b18c681-92d5-4c7f-802c-df413b6504c8
|
||||
api_secret: jTk5gSHTqDIZng1zh2z6jrT8JjVgCKsmV8_7NyESbQk
|
||||
api_debug: true
|
||||
api_rate_limit_max_requests: 30
|
||||
api_rate_limit_window_seconds: 10.0
|
||||
poll_max_retries: 1
|
||||
poll_interval: 0.5
|
||||
target_project_ids:
|
||||
# 请替换为实际的项目ID,至少需要一个
|
||||
- "0f9c3e22-f4bb-4803-825a-4f238eeb06d5"
|
||||
- "f3e02e84-e81c-4aa6-88d4-f5aa108c8227"
|
||||
handler_configs:
|
||||
supplier: {}
|
||||
persist:
|
||||
backend: sqlite
|
||||
db_path: ${PROJECT_ROOT}/test_results/sync_state_machine/simple_pipeline_sm.db
|
||||
enable: true
|
||||
wipe_on_start: false
|
||||
logging:
|
||||
initialize: true
|
||||
file_dir: ${PROJECT_ROOT}/test_results/sync_state_machine
|
||||
file_name_pattern: simple_pipeline_sm_{timestamp}.log
|
||||
level: 20
|
||||
strategies:
|
||||
company:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- credit_code
|
||||
depend_fields: {}
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: create_local
|
||||
update_direction: pull
|
||||
supplier:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- credit_code
|
||||
depend_fields: {}
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: create_local
|
||||
update_direction: pull
|
||||
project:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: false
|
||||
auto_bind_fields: []
|
||||
pre_bind_data_id: []
|
||||
depend_fields:
|
||||
company_id: company
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- company_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
company_id: supplier
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract_change:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
- change_time
|
||||
- title
|
||||
depend_fields:
|
||||
project_id: project
|
||||
contract_id: contract
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
construction_task:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
- task_type
|
||||
depend_fields:
|
||||
contract_id: contract
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
construction_task_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: construction_task
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
material:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
- material_type
|
||||
depend_fields:
|
||||
contract_id: contract
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
material_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: material
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract_settlement:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
depend_fields:
|
||||
contract_id: contract
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract_settlement_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: contract_settlement
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
personnel:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
contract_id: contract
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
personnel_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: personnel
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
preparation:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
production:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
lar:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
lar_change:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- change_time
|
||||
- title
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
project_detail_data:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- key
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push # 未在 field_direction_overrides 中列出的 key 默认 push
|
||||
field_direction_key: key # 以节点 data.key 字段值作为方向查表键
|
||||
field_direction_overrides:
|
||||
ensure_production: pull # 远程 → 本地
|
||||
climb_production: pull # 远程 → 本地
|
||||
challenge_production: pull # 远程 → 本地
|
||||
units:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- serial_number
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
@@ -0,0 +1,284 @@
|
||||
node_types:
|
||||
- company
|
||||
- user
|
||||
- supplier
|
||||
- project
|
||||
- contract
|
||||
- contract_change
|
||||
- construction_task
|
||||
- construction_task_detail
|
||||
- material
|
||||
- material_detail
|
||||
- contract_settlement
|
||||
- contract_settlement_detail
|
||||
- personnel
|
||||
- personnel_detail
|
||||
- preparation
|
||||
- production
|
||||
- lar
|
||||
- lar_change
|
||||
- project_detail_data
|
||||
- units
|
||||
local_datasource:
|
||||
type: jsonl
|
||||
jsonl_dir: ${PROJECT_ROOT}/filtered_datasource/datasource/filtered
|
||||
read_only: false
|
||||
target_project_ids: []
|
||||
handler_configs: {}
|
||||
remote_datasource:
|
||||
type: jsonl
|
||||
jsonl_dir: ${PROJECT_ROOT}/remote_datasource/datasource
|
||||
read_only: false
|
||||
target_project_ids: []
|
||||
handler_configs: {}
|
||||
persist:
|
||||
backend: sqlite
|
||||
db_path: ${PROJECT_ROOT}/test_results/sync_state_machine/full_sync_pipeline_jsonl_sm.db
|
||||
enable: true
|
||||
wipe_on_start: false
|
||||
logging:
|
||||
initialize: true
|
||||
file_dir: ${PROJECT_ROOT}/test_results/sync_state_machine
|
||||
file_name_pattern: jsonl_pipeline_sm_{timestamp}.log
|
||||
level: 20
|
||||
strategies:
|
||||
company:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- credit_code
|
||||
depend_fields: {}
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
user:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- username
|
||||
depend_fields: {}
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
supplier:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- credit_code
|
||||
depend_fields: {}
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
project:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- name
|
||||
depend_fields:
|
||||
company_id: company
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- company_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
company_id: supplier
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract_change:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
- change_time
|
||||
- title
|
||||
depend_fields:
|
||||
project_id: project
|
||||
contract_id: contract
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
construction_task:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
- task_type
|
||||
depend_fields:
|
||||
contract_id: contract
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
construction_task_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: construction_task
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
material:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
- material_type
|
||||
depend_fields:
|
||||
contract_id: contract
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
material_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: material
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract_settlement:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- contract_id
|
||||
depend_fields:
|
||||
contract_id: contract
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
contract_settlement_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: contract_settlement
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
personnel:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
contract_id: contract
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
personnel_detail:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- parent_id
|
||||
- date
|
||||
depend_fields:
|
||||
parent_id: personnel
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
preparation:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
production:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- code
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: none
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
lar:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
lar_change:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- change_time
|
||||
- title
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
project_detail_data:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- key
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
units:
|
||||
skip_sync: false
|
||||
config:
|
||||
auto_bind: true
|
||||
auto_bind_fields:
|
||||
- project_id
|
||||
- serial_number
|
||||
depend_fields:
|
||||
project_id: project
|
||||
local_orphan_action: create_remote
|
||||
remote_orphan_action: none
|
||||
update_direction: push
|
||||
@@ -0,0 +1,108 @@
|
||||
from pydantic import BaseModel, Field, ValidationError, model_validator
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Optional, TypeVar, Generic, List
|
||||
from pydantic import BaseModel, Field, model_serializer
|
||||
|
||||
class BaseResponseWithID(BaseModel):
|
||||
"""
|
||||
Mixin: 统一处理输入中的 id/_id -> id
|
||||
约束:
|
||||
- 若 id 与 _id 同时出现且值不同 -> 报错
|
||||
- 若仅 _id 出现 -> 转成 id
|
||||
- 若两者都缺失 -> 报错
|
||||
- 最终保证存在 id: str
|
||||
"""
|
||||
id: str = Field(..., description="资源唯一标识ID")
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def normalize_id(cls, data: Any) -> Any:
|
||||
# 仅处理 dict-like 输入;其他情况交给 Pydantic 默认流程
|
||||
if not isinstance(data, dict):
|
||||
return data
|
||||
|
||||
has_id = "id" in data
|
||||
has__id = "_id" in data
|
||||
|
||||
if has_id and has__id:
|
||||
if str(data["id"]) != str(data["_id"]):
|
||||
raise ValidationError([
|
||||
{
|
||||
"type": "value_error",
|
||||
"loc": ("id",),
|
||||
"msg": "id and _id both provided but not equal",
|
||||
"input": data.get("id"),
|
||||
}
|
||||
], cls)
|
||||
# 相同则优先保留 id,去掉 _id
|
||||
data = {**data}
|
||||
data.pop("_id", None)
|
||||
return data
|
||||
|
||||
if has__id and not has_id:
|
||||
# 将 _id 统一映射为 id
|
||||
data = {**data}
|
||||
data["id"] = str(data["_id"])
|
||||
data.pop("_id", None)
|
||||
return data
|
||||
|
||||
if not has_id and not has__id:
|
||||
raise ValidationError([
|
||||
{
|
||||
"type": "value_error.missing",
|
||||
"loc": ("id",),
|
||||
"msg": "id or _id is required",
|
||||
"input": data,
|
||||
}
|
||||
], cls)
|
||||
|
||||
# 默认返回(已有 id)
|
||||
return data
|
||||
|
||||
class RequestApprovalMixin(BaseModel):
|
||||
"""
|
||||
请求审批相关的基础模型
|
||||
"""
|
||||
pass
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
# def _build_full_response_dict(code: int, message: Optional[str], data: Any) -> dict:
|
||||
# """构建与 __orjson__ 完全一致的响应字典"""
|
||||
# # 处理 data 的序列化(与 __orjson__ 逻辑同步)
|
||||
# if data is None:
|
||||
# clean_data = {}
|
||||
# elif isinstance(data, BaseModel):
|
||||
# clean_data = data.model_dump()
|
||||
# else:
|
||||
# clean_data = data
|
||||
# return {
|
||||
# "code": code,
|
||||
# "message": message,
|
||||
# "data": clean_data
|
||||
# }
|
||||
|
||||
class Success(BaseModel, Generic[T]):
|
||||
code: int = 200
|
||||
message: Optional[str] = "OK"
|
||||
data: Optional[T] = None
|
||||
|
||||
# def __init__(self, **kwargs):
|
||||
# super().__init__(**kwargs)
|
||||
# # 自动捕获完整响应结构到 push_log.result
|
||||
# push_log = current_push_log.get()
|
||||
# if push_log is not None:
|
||||
# full_response = _build_full_response_dict(self.code, self.message, self.data)
|
||||
# push_log.result = full_response
|
||||
#
|
||||
class Fail(BaseModel):
|
||||
code: int = 400
|
||||
message: Optional[str] = None
|
||||
data: Optional[Any] = Field(default_factory=dict)
|
||||
|
||||
class PaginatedList(BaseModel, Generic[T]):
|
||||
list: List[T] = Field(default_factory=list)
|
||||
total: int = 0
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
@@ -0,0 +1,13 @@
|
||||
from datetime import datetime, date
|
||||
import pytz
|
||||
|
||||
def get_current_date(date_formate='%Y-%m-%d'):
|
||||
"""
|
||||
获取当前日期字符串,格式化为指定格式,默认格式为'YYYY-MM-DD'
|
||||
"""
|
||||
tz = pytz.timezone('Asia/Shanghai') # 设置为中国时区
|
||||
current_date = datetime.now(tz)
|
||||
return current_date.strftime(date_formate)
|
||||
|
||||
def datetime_date(date: str) -> date:
|
||||
return datetime.strptime(date, "%Y-%m-%d").date()
|
||||
@@ -0,0 +1,9 @@
|
||||
from enum import Enum
|
||||
|
||||
class ApprovalStatus(str, Enum):
|
||||
REGISTERED = "registered"
|
||||
UNDER_REVIEW = "under_review"
|
||||
APPROVED = "approved"
|
||||
REJECTED = "rejected"
|
||||
PENDING_CONFIRM = "pending_confirm"
|
||||
CONFIRMED = "confirmed"
|
||||
@@ -0,0 +1,178 @@
|
||||
"""
|
||||
推送接口通用schema
|
||||
|
||||
## 响应相关
|
||||
1. BaseResponseSchema: 所有接口响应的基础schema
|
||||
2. BasePushResponseSchema: 推送接口响应的基础schema,包含push_id
|
||||
3. PushResultSchema: 查询推送结果的schema
|
||||
|
||||
## 请求相关
|
||||
4. BaseCreateRequestSchema[T]: 创建资源的基础请求schema(泛型),业务数据在data字段
|
||||
5. BaseUpdateRequestSchema[T]: 更新资源的基础请求schema(泛型),业务数据在data字段
|
||||
6. BaseDeleteRequestSchema: 删除资源的基础请求schema,只需resource_id
|
||||
7. BulkPushRequestSchema: 批量推送请求的schema
|
||||
|
||||
## 说明
|
||||
- 所有元数据字段(timestamp, nonce, signature, uid, push_id)在请求体最外层
|
||||
- push_id使用UUIDv7格式,支持时间排序,同时作为幂等键和查询键
|
||||
- 业务数据嵌套在data字段中(删除操作除外,只需resource_id)
|
||||
- 所有业务Schema必须继承BasePushData,确保包含project_type字段
|
||||
- resource_id在外层,用于标识要操作的资源(更新/删除时必填)
|
||||
- 使用泛型T可快速定义各业务的请求schema,T必须继承BasePushData
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import TypeVar, Generic, Optional, List, Dict, Any
|
||||
from ..project.enums import ProjectType
|
||||
|
||||
# 定义泛型
|
||||
T = TypeVar('T', bound='BasePushData')
|
||||
|
||||
# ==================== 业务数据基类 ====================
|
||||
|
||||
class BasePushData(BaseModel):
|
||||
"""
|
||||
所有推送业务数据的基类
|
||||
|
||||
所有业务Schema必须继承此类,确保包含project_type字段
|
||||
"""
|
||||
project_type: ProjectType = Field(..., description="项目类型:offshore_wind/pumped_storage/photovoltaic等")
|
||||
|
||||
|
||||
# ==================== Mixin ====================
|
||||
|
||||
class SignatureMixin(BaseModel):
|
||||
"""签名字段混入"""
|
||||
timestamp: int = Field(..., description="毫秒级 Unix 时间戳")
|
||||
nonce: str = Field(..., description="随机字符串,防止重放攻击")
|
||||
sign: str = Field(..., description="签名字符串")
|
||||
uid: str = Field(..., description="集团侧用户id")
|
||||
|
||||
|
||||
class PushRequestMixin(BaseModel):
|
||||
"""推送ID字段混入"""
|
||||
push_id: str = Field(..., description="推送ID,客户端生成的唯一标识(UUIDv7,支持时间排序)")
|
||||
|
||||
|
||||
# ==================== 响应相关 ====================
|
||||
|
||||
class BaseResponseSchema(BaseModel):
|
||||
"""所有接口响应的基础schema"""
|
||||
code: int = 200
|
||||
message: Optional[str] = "OK"
|
||||
data: Optional[T] = None
|
||||
|
||||
|
||||
class BasePushResponseSchema(BaseModel):
|
||||
"""推送接口响应的基础schema"""
|
||||
biz_id: str | None = Field(None, description="资源ID(create操作成功后返回新创建的ID,update/delete返回原ID)")
|
||||
|
||||
|
||||
class PushResultSchema(BaseModel):
|
||||
"""查询推送结果的schema"""
|
||||
push_id: str = Field(..., description="推送ID(客户端生成的UUIDv7)")
|
||||
status: str = Field(..., description="推送状态:queued/processing/success/failed")
|
||||
result: Dict[str, Any] | None = Field(None, description="处理结果(成功时包含created_id等信息)")
|
||||
error: str | None = Field(None, description="错误信息(失败时)")
|
||||
created_at: str = Field(..., description="推送创建时间(ISO 8601格式)")
|
||||
updated_at: str = Field(..., description="推送更新时间(ISO 8601格式)")
|
||||
|
||||
|
||||
class PushIdsSchema(BaseModel):
|
||||
"""支持从请求体接收的 push_ids 列表字符串(逗号拼接)"""
|
||||
push_ids: Optional[str] = Field(None, description="推送id字符串逗号拼接")
|
||||
|
||||
|
||||
# ==================== 请求相关 ====================
|
||||
|
||||
class BaseCreateRequestSchema(SignatureMixin, PushRequestMixin, BaseModel, Generic[T]):
|
||||
"""
|
||||
创建资源的基础请求schema(泛型)
|
||||
|
||||
泛型T必须继承BasePushData,确保包含project_type字段
|
||||
|
||||
使用示例:
|
||||
class ProjectInputSchema(BasePushData):
|
||||
name: str = Field(...)
|
||||
capacity: float = Field(...)
|
||||
|
||||
class ProjectCreateRequest(BaseCreateRequestSchema[ProjectInputSchema]):
|
||||
pass
|
||||
"""
|
||||
# 业务数据(嵌套)
|
||||
data: T = Field(..., description="业务数据")
|
||||
|
||||
|
||||
class BaseUpdateRequestSchema(SignatureMixin, PushRequestMixin, BaseModel, Generic[T]):
|
||||
"""
|
||||
更新资源的基础请求schema(泛型)
|
||||
|
||||
泛型T必须继承BasePushData,确保包含project_type字段
|
||||
resource_id在外层,用于标识要更新的资源
|
||||
|
||||
使用示例:
|
||||
class ProjectInputSchema(BasePushData):
|
||||
name: str = Field(...)
|
||||
capacity: float = Field(...)
|
||||
|
||||
class ProjectUpdateRequest(BaseUpdateRequestSchema[ProjectInputSchema]):
|
||||
pass
|
||||
"""
|
||||
# 资源标识
|
||||
biz_id: str = Field(..., description="要更新的资源ID,类型id,如project传project_id,unit传unit_id")
|
||||
|
||||
# 业务数据(嵌套)
|
||||
data: T = Field(..., description="业务数据(只需包含要更新的字段)")
|
||||
|
||||
|
||||
class BaseDeleteRequestSchema(SignatureMixin, PushRequestMixin, BaseModel):
|
||||
"""
|
||||
删除资源的基础请求schema
|
||||
|
||||
使用示例:
|
||||
class ProjectDeleteRequest(BaseDeleteRequestSchema):
|
||||
pass
|
||||
"""
|
||||
|
||||
# 资源标识
|
||||
biz_id: str = Field(..., description="要删除的资源ID")
|
||||
|
||||
|
||||
class BulkPushItem(PushRequestMixin, BaseModel):
|
||||
"""
|
||||
批量推送中的单个项目
|
||||
|
||||
注意:
|
||||
- action为create时:data必填,resource_id留空
|
||||
- action为update时:data和resource_id都必填
|
||||
- action为delete时:resource_id必填,data留空
|
||||
- data必须继承BasePushData,确保包含project_type字段
|
||||
"""
|
||||
action: str = Field(..., description="操作类型:create/update/delete")
|
||||
resource_id: str | None = Field(None, description="资源ID(update/delete时必填,create时留空)")
|
||||
data: BasePushData | None = Field(None, description="业务数据(create/update时必填,delete时留空,必须包含project_type字段)")
|
||||
|
||||
|
||||
class BulkPushItemResult(BaseModel):
|
||||
"""批量推送中单个项目的处理结果"""
|
||||
push_id: str = Field(..., description="推送ID(对应请求中的push_id)")
|
||||
status: str = Field(..., description="处理状态:queued/processing/success/failed")
|
||||
resource_id: str | None = Field(None, description="资源ID(create成功时返回新ID,update/delete返回原ID)")
|
||||
error: str | None = Field(None, description="错误信息(失败时)")
|
||||
|
||||
|
||||
class BulkPushRequestSchema(SignatureMixin, BaseModel):
|
||||
"""
|
||||
批量推送请求的schema
|
||||
|
||||
一次请求可推送多条数据,每条都有独立的幂等键和操作类型
|
||||
"""
|
||||
# 批量数据
|
||||
items: List[BulkPushItem] = Field(..., description="批量推送的数据列表")
|
||||
|
||||
|
||||
class BulkPushResponseSchema(BaseResponseSchema):
|
||||
"""批量推送响应的schema"""
|
||||
batch_id: str = Field(..., description="批量推送的批次ID")
|
||||
total: int = Field(..., description="总数量")
|
||||
results: List[BulkPushItemResult] = Field(..., description="每条数据的处理结果,包含push_id和resource_id")
|
||||
@@ -0,0 +1,85 @@
|
||||
from datetime import datetime
|
||||
from typing import Annotated
|
||||
from pydantic import AfterValidator
|
||||
from functools import lru_cache
|
||||
import re
|
||||
|
||||
# 预编译正则表达式,避免重复编译
|
||||
DATE_PATTERN = re.compile(r'^\d{4}-\d{2}-\d{2}$')
|
||||
TIMESTAMP_PATTERNS = {
|
||||
'iso_z': re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z$'),
|
||||
'iso_offset': re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+\+00:00$'),
|
||||
'simple_space': re.compile(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'),
|
||||
'simple_t': re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$'),
|
||||
}
|
||||
|
||||
@lru_cache(maxsize=1024) # 缓存最近1024个不同的日期
|
||||
def _validate_date_cached(v: str) -> str:
|
||||
"""缓存版本的日期验证"""
|
||||
# 快速格式检查(避免无效字符串进入 strptime)
|
||||
if not DATE_PATTERN.match(v):
|
||||
raise ValueError(f"日期格式应为 YYYY-MM-DD,实际为: {v}")
|
||||
|
||||
# 验证日期有效性(例如排除 2023-02-30)
|
||||
datetime.strptime(v, "%Y-%m-%d")
|
||||
return v
|
||||
|
||||
def validate_date(v: str) -> str:
|
||||
"""校验日期格式为 YYYY-MM-DD"""
|
||||
if v is None or v == "":
|
||||
return v
|
||||
|
||||
return _validate_date_cached(v)
|
||||
|
||||
@lru_cache(maxsize=2048) # 时间戳变化更多,给更大的缓存
|
||||
def _validate_timestamp_cached(v: str) -> str:
|
||||
"""缓存版本的时间戳验证"""
|
||||
# 按常见程度排序,优先检查最可能的格式
|
||||
if TIMESTAMP_PATTERNS['iso_z'].match(v):
|
||||
datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
elif TIMESTAMP_PATTERNS['simple_space'].match(v):
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
elif TIMESTAMP_PATTERNS['simple_t'].match(v):
|
||||
datetime.strptime(v, "%Y-%m-%dT%H:%M:%S")
|
||||
elif TIMESTAMP_PATTERNS['iso_offset'].match(v):
|
||||
datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%f+00:00")
|
||||
else:
|
||||
# 兜底逻辑:如果正则都不匹配,尝试原来的逻辑
|
||||
try:
|
||||
if v.endswith('Z'):
|
||||
datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
elif v.endswith('+00:00'):
|
||||
datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%f+00:00")
|
||||
else:
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
datetime.strptime(v, "%Y-%m-%dT%H:%M:%S")
|
||||
except ValueError:
|
||||
raise ValueError("时间戳格式应为 YYYY-MM-DDTHH:MM:SS.sssZ、+00:00、YYYY-MM-DD HH:MM:SS 或 YYYY-MM-DDTHH:MM:SS")
|
||||
|
||||
return v
|
||||
|
||||
def validate_timestamp(v: str) -> str:
|
||||
"""校验时间戳格式"""
|
||||
if v is None or v == "":
|
||||
return v
|
||||
|
||||
return _validate_timestamp_cached(v)
|
||||
|
||||
# 定义新类型
|
||||
DateStr = Annotated[str, AfterValidator(validate_date)]
|
||||
TimestampStr = Annotated[str, AfterValidator(validate_timestamp)]
|
||||
|
||||
# 可选:提供缓存统计功能用于调试
|
||||
def get_cache_stats():
|
||||
"""获取缓存统计信息,用于性能调试"""
|
||||
return {
|
||||
'date_cache': _validate_date_cached.cache_info(),
|
||||
'timestamp_cache': _validate_timestamp_cached.cache_info(),
|
||||
}
|
||||
|
||||
def clear_validation_cache():
|
||||
"""清空验证缓存(用于测试或内存清理)"""
|
||||
_validate_date_cached.cache_clear()
|
||||
_validate_timestamp_cached.cache_clear()
|
||||
@@ -0,0 +1,40 @@
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
|
||||
class CompanyResponse(BaseResponseWithID):
|
||||
code: str = Field(..., description="公司编码")
|
||||
company_type: str = Field(..., description="公司类型")
|
||||
name: str = Field(..., description="公司名称")
|
||||
short_name: str = Field(..., description="公司简称")
|
||||
parent_id: Optional[str] = Field(None, description="父公司ID")
|
||||
path: List[str] = Field(default_factory=list, description="公司路径 [..., 上级id, 本身id]")
|
||||
path_name: List[str] = Field(default_factory=list, description="公司路径名称 [..., 上级名称, 本身名称]")
|
||||
province: Optional[str] = Field(None, description="省份编码") # 存省份编码
|
||||
city: Optional[str] = Field(None, description="城市编码") # 存城市编码
|
||||
sort: int = Field(0, description="排序")
|
||||
status: str = Field("", description="公司状态")
|
||||
company_nature: Optional[list] = Field(..., description="公司性质")
|
||||
credit_code: Optional[str] = Field(None, description="信用代码", examples=["914403007109310121"])
|
||||
|
||||
city_name: Optional[str] = Field(None, description="城市名称", examples=[None])
|
||||
province_name: Optional[str] = Field(None, description="省份名称", examples=[None])
|
||||
parent_name: Optional[str] = Field(None, description="父级公司名称", examples=[None])
|
||||
|
||||
@field_validator(
|
||||
"path",
|
||||
"path_name",
|
||||
mode="before"
|
||||
)
|
||||
def formate_null_to_list(cls, field_value):
|
||||
if field_value is None:
|
||||
return []
|
||||
return field_value
|
||||
|
||||
|
||||
class CompanyListResponse(BaseModel):
|
||||
page: int
|
||||
page_size: int
|
||||
total: int
|
||||
list: List[CompanyResponse] = []
|
||||
@@ -0,0 +1,121 @@
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
class PlanNode(BaseModel):
|
||||
date: DateStr = Field(..., description="计划节点时间", examples=["2024-01-01"])
|
||||
quantity: float = Field(..., description="计划完成量", examples=[100.0])
|
||||
is_audit: Optional[bool] = Field(False, description="是否已审核", examples=[False])
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_price(cls, v):
|
||||
"""验证金额必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='计划完成量不能小于等于0')
|
||||
return v
|
||||
|
||||
class ConstructionResponse(BaseResponseWithID):
|
||||
"""
|
||||
施工任务模型,存储在CouchDB中的施工任务文档
|
||||
"""
|
||||
id : str = Field(..., description="施工任务ID")
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: Optional[str] = Field(None, description="所属合同ID", examples=["contract456"])
|
||||
show_name: str = Field(..., description="展示名称", examples=["桩基础施工任务"])
|
||||
construction_section: str = Field(..., description="施工区域", examples=["GF"])
|
||||
status: Optional[int] = Field(None, description="施工状态", examples=[0])
|
||||
task_type: str = Field(..., description="施工任务类型", examples=["zjcsgg"])
|
||||
plan_start_date: Optional[DateStr] = Field(None, description="计划开工时间", examples=["2024-01-01"])
|
||||
plan_complete_date: Optional[DateStr] = Field(None, description="计划完工时间", examples=["2024-06-01"])
|
||||
actual_complete_date: Optional[DateStr] = Field(None, description="实际完工时间", examples=["2024-05-30"])
|
||||
complete_quantity: float = Field(0.0, description="实际完成量累计", examples=[0.0])
|
||||
complete_rate: float = Field(0.0, description="实际完成率(%)", examples=[0.0])
|
||||
contract_quantity: Optional[float] = Field(None, description="设计量", examples=[1000.0])
|
||||
plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
|
||||
statistic_date: Optional[DateStr] = Field(None, description="统计节点时间", examples=["2024-05-31"])
|
||||
# sort: int = Field(0, description="排序字段", examples=[0])
|
||||
is_crucial:Optional[bool] = Field(False, description="是否为关键线路")
|
||||
# 2025-10-20新增字段,延迟时间
|
||||
delay_days: Optional[int] = Field(None, description="延迟时间(天)", examples=[0])
|
||||
|
||||
class ConstructionCreate(BaseModel):
|
||||
"""
|
||||
施工任务创建模型
|
||||
不对应operation
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: Optional[str] = Field(None, description="所属合同ID", examples=["contract456"])
|
||||
show_name: str = Field(..., description="展示名称", examples=["桩基础施工任务"])
|
||||
construction_section: str = Field(..., description="施工区域", examples=["GF"])
|
||||
task_type: str = Field(..., description="施工任务类型", examples=["zjcsgg"])
|
||||
is_crucial:Optional[bool] = Field(False, description="是否为关键线路")
|
||||
|
||||
|
||||
|
||||
class ConstructionUpdate(BaseModel):
|
||||
"""
|
||||
施工任务更新模型
|
||||
CONSTRUCTION_BASE_INFO = "construction.base_info"
|
||||
"""
|
||||
id: str = Field(..., description="施工任务ID")
|
||||
contract_id: Optional[str] = Field(None, description="所属合同ID", examples=["contract456"])
|
||||
show_name: str | None = Field(None, description="展示名称(仅QT类施工可以修改名称)", examples=["桩基础施工任务"])
|
||||
is_crucial:bool | None = Field(False, description="是否为关键线路")
|
||||
|
||||
class ConstructionPlanUpdate(BaseModel):
|
||||
"""
|
||||
施工计划更新模型
|
||||
对应 CONSTRUCTION_PLAN = "construction.plan"
|
||||
|
||||
业务逻辑说明:
|
||||
- API要求计划节点时间必须晚于计划开工日期(不能等于)
|
||||
- 自动清理脏数据:如果 plan_node 有2个或以上节点,删除:
|
||||
1. 开头节点:如果其 date 等于 plan_start_date
|
||||
2. 结尾节点:如果其 date 等于 plan_complete_date
|
||||
- 这样避免提交包含边界节点的数据导致API报错
|
||||
"""
|
||||
id: str = Field(..., description="施工任务ID")
|
||||
plan_start_date: Optional[str] = Field(None, description="计划开工时间", examples=["2024-01-01"])
|
||||
plan_complete_date: Optional[str] = Field(None, description="计划完工时间", examples=["2024-01-01"])
|
||||
contract_quantity: float = Field(..., description="设计量")
|
||||
plan_node: Optional[List[PlanNode]] = Field(default_factory=list, description="计划节点列表")
|
||||
|
||||
@field_validator("contract_quantity")
|
||||
def validate_price(cls, v):
|
||||
"""验证金额必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='设计量不能小于0')
|
||||
return v
|
||||
|
||||
@model_validator(mode='after')
|
||||
def clean_plan_nodes(self):
|
||||
"""
|
||||
清理计划节点列表中的边界节点
|
||||
|
||||
如果 plan_node 有2个或以上节点,删除:
|
||||
- 开头节点:date 等于 plan_start_date
|
||||
- 结尾节点:date 等于 plan_complete_date
|
||||
|
||||
这避免了API报错"计划节点时间必须晚于计划开工日期"
|
||||
"""
|
||||
if not self.plan_node or len(self.plan_node) < 2:
|
||||
return self
|
||||
|
||||
cleaned_nodes = list(self.plan_node)
|
||||
|
||||
# 删除开头的边界节点
|
||||
if (self.plan_start_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[0].date == self.plan_start_date):
|
||||
cleaned_nodes.pop(0)
|
||||
|
||||
# 删除结尾的边界节点
|
||||
if (self.plan_complete_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[-1].date == self.plan_complete_date):
|
||||
cleaned_nodes.pop()
|
||||
|
||||
self.plan_node = cleaned_nodes
|
||||
return self
|
||||
@@ -0,0 +1,133 @@
|
||||
from pydantic import BaseModel, Field,field_validator
|
||||
from ..common.datetime import get_current_date
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.enums import ApprovalStatus
|
||||
from datetime import datetime
|
||||
|
||||
class ConstructionDetailResponse(BaseResponseWithID):
|
||||
"""
|
||||
物资明细返回值
|
||||
"""
|
||||
id: str = Field(..., description="施工任务明细ID")
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属施工任务ID", examples=["task789"])
|
||||
rate: Optional[float] = Field(None, description="实际完成率", examples=[0.0])
|
||||
quantity: float = Field(0.0, ge=0, description="实际完成量累计", examples=[0.0])
|
||||
date: DateStr = Field(..., description="节点日期", examples=["2024-05-31"])
|
||||
status: Optional[int] = Field(None, description="进度状态", examples=[0])
|
||||
change_count: int = Field(0, description="变更次数", examples=[0])
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部完成", examples=[False]
|
||||
)
|
||||
|
||||
class ConstructionDetailCreate(BaseModel):
|
||||
"""
|
||||
施工明细创建模型
|
||||
CONSTRUCTION_DETAIL = "construction.detail"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属施工任务ID", examples=["task789"])
|
||||
quantity: float = Field(0.0, ge=0, description="实际完成量累计", examples=[0.0])
|
||||
date: DateStr = Field(..., description="节点日期", examples=["2024-05-31"])
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
is_complete: Optional[bool] = Field(
|
||||
False, description="是否为全部完成", examples=[False]
|
||||
)
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='实际完成量累计不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='节点日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
|
||||
class ConstructionDetailUpdate(BaseModel):
|
||||
"""
|
||||
施工明细更新模型
|
||||
CONSTRUCTION_DETAIL = "construction.detail"
|
||||
"""
|
||||
id: str = Field(..., description="施工任务明细ID")
|
||||
quantity: Optional[float] = Field(None, ge=0, description="实际完成量累计", examples=[0.0])
|
||||
date: Optional[DateStr] = Field(None, description="节点日期", examples=["2024-05-31"])
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部完成", examples=[False]
|
||||
)
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus | None = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v is None:
|
||||
return None
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='实际完成量累计不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v is None:
|
||||
return None
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='节点日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class ConstructionDetailBulkUpdate(BaseModel):
|
||||
detail_list: List[ConstructionDetailUpdate]
|
||||
@@ -0,0 +1,122 @@
|
||||
from pydantic import BaseModel, Field,field_validator
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.datetime import datetime_date,get_current_date
|
||||
from fastapi import HTTPException
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
class ContractResponse(BaseResponseWithID):
|
||||
"""
|
||||
合同返回信息
|
||||
"""
|
||||
id : str = Field(..., description="合同ID")
|
||||
project_id: str = Field("", description="所属项目ID")
|
||||
name: str = Field("", description="合同名称")
|
||||
short_name: str = Field("", description="合同简称")
|
||||
code: str = Field("", description="合同编码")
|
||||
contract_type: str = Field("", description="合同类型")
|
||||
|
||||
currency: str = Field("CNY", description="币种")
|
||||
manager_name: str = Field("", description="负责人姓名")
|
||||
manager_phone: str = Field("", description="负责人电话")
|
||||
|
||||
sign_company: str = Field("", description="签订公司")
|
||||
company_id: str = Field("", description="签订公司id")
|
||||
sign_date: DateStr = Field("", description="签订日期", examples=["2023-10-01"])
|
||||
credit_code: Optional[str] = Field("", description="签订公司信用代码")
|
||||
|
||||
total_price: float = Field(0.0, description="合同金额")
|
||||
sub_name: Optional[str] = Field(None, description="合同子标题")
|
||||
|
||||
|
||||
class ContractCreate(BaseModel):
|
||||
"""
|
||||
创建合同
|
||||
CONTRACT = "contract"
|
||||
"""
|
||||
name: str|None = Field(None, description="合同名称")
|
||||
sub_name:str|None= Field(None, description="合同子标题")
|
||||
code: str = Field("", description="合同编码")
|
||||
contract_type: str = Field("", description="合同类型")
|
||||
|
||||
project_id: str = Field("", description="所属项目ID")
|
||||
|
||||
currency: str = Field("CNY", description="币种")
|
||||
manager_name: str = Field("", description="负责人姓名")
|
||||
manager_phone: str = Field("", description="负责人电话")
|
||||
|
||||
sign_company: str = Field("", description="签订公司")
|
||||
company_id: Optional[str] = Field(None, description="签订公司id")
|
||||
sign_date: DateStr = Field("", description="签订日期", examples=["2023-10-01"])
|
||||
credit_code: Optional[str] = Field(None, description="签订公司信用代码")
|
||||
|
||||
total_price: float = Field(0.0, description="合同金额")
|
||||
|
||||
@field_validator("total_price")
|
||||
def validate_price(cls, v):
|
||||
"""验证金额必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='合同金额不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator('sign_date')
|
||||
def validate_actual_date_not_future(cls, v: str) -> str:
|
||||
if v == "":
|
||||
return ""
|
||||
try:
|
||||
actual = datetime_date(v)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail='日期格式为(YYYY-MM-DD)')
|
||||
|
||||
today = datetime_date(get_current_date())
|
||||
if actual > today:
|
||||
raise HTTPException(status_code=400, detail='签约日期不能晚于今天')
|
||||
return v
|
||||
|
||||
class ContractUpdate(BaseModel):
|
||||
"""
|
||||
更新合同
|
||||
CONTRACT = "contract"
|
||||
"""
|
||||
id : str = Field(..., description="合同ID")
|
||||
sub_name:str|None= Field(None, description="合同子标题")
|
||||
|
||||
currency: str|None = Field(None, description="币种")
|
||||
|
||||
manager_name: str|None= Field(None, description="负责人姓名")
|
||||
manager_phone: str|None= Field(None, description="负责人电话")
|
||||
|
||||
sign_company: str|None= Field(None, description="签订公司")
|
||||
company_id: Optional[str] = Field(None, description="签订公司id")
|
||||
sign_date: str|None = Field(None, description="签订日期", examples=["2023-10-01"])
|
||||
credit_code: Optional[str] = Field(None, description="签订公司信用代码")
|
||||
|
||||
total_price: float|None= Field(None, description="合同金额")
|
||||
|
||||
@field_validator("total_price")
|
||||
def validate_price(cls, v):
|
||||
"""验证金额必须为非负数"""
|
||||
if v is None:
|
||||
return None
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='合同金额不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator('sign_date')
|
||||
def validate_actual_date_not_future(cls, v: str):
|
||||
if v is None:
|
||||
return None
|
||||
if v == "":
|
||||
return ""
|
||||
try:
|
||||
actual = datetime_date(v)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail='日期格式为(YYYY-MM-DD)')
|
||||
|
||||
today = datetime_date(get_current_date())
|
||||
if actual > today:
|
||||
raise HTTPException(status_code=400, detail='签约日期不能晚于今天')
|
||||
return v
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
from pydantic import Field, BaseModel,field_validator,model_validator
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
class PlanNode(BaseModel):
|
||||
date: DateStr = Field(..., description="计划节点时间", examples=["2024-01-01"])
|
||||
quantity: float = Field(..., description="计划完成量", examples=[100.0])
|
||||
is_audit: Optional[bool] = Field(False, description="是否已审核", examples=[False])
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证计划完成量必须大于0"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='计划完成量不能小于0')
|
||||
return v
|
||||
|
||||
class ContractSettlementResponse(BaseResponseWithID):
|
||||
"""
|
||||
合同结算返回
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: str = Field(..., description="所属合同ID", examples=["contract456"])
|
||||
contract_type: Optional[str] = Field(None, description="合同类型")
|
||||
show_name: Optional[str] = Field(None, description="合同简称", examples=["主变采购合同"])
|
||||
complete_price: float = Field(0.0, description="实际完成金额", examples=[100000.0])
|
||||
contract_price: float = Field(0.0, description="合同金额", examples=[120000.0])
|
||||
actual_complete_date: Optional[DateStr] = Field(None, description="实际结束时间", examples=["2024-06-30"])
|
||||
actual_start_date: Optional[DateStr] = Field(None, description="实际开始时间", examples=["2024-01-01"])
|
||||
plan_complete_date: Optional[DateStr] = Field(None, description="计划结束时间", examples=["2024-06-30"])
|
||||
plan_start_date: Optional[DateStr] = Field(None, description="计划开始时间", examples=["2024-01-01"])
|
||||
plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
|
||||
status: Optional[int] = Field(None,description="供货状态", examples=[0])
|
||||
|
||||
# 2025-10-20新增字段,延迟时间
|
||||
delay_days: Optional[int] = Field(None, description="延迟时间(天)", examples=[0])
|
||||
statistic_date: Optional[DateStr] = Field(
|
||||
None, description="统计节点截止日期", examples=["2024-05-31"]
|
||||
)
|
||||
|
||||
class ContractSettlementCreate(BaseModel):
|
||||
"""
|
||||
合同结算创建模型
|
||||
CONTRACT_SETTLEMENT_BASE_INFO = "contract_settlement.base_info"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: str = Field(..., description="所属合同ID", examples=["contract456"])
|
||||
show_name: Optional[str] = Field(None, description="合同简称", examples=["主变采购合同"])
|
||||
|
||||
class ContractSettlementUpdate(BaseModel):
|
||||
"""
|
||||
合同结算更新模型
|
||||
CONTRACT_SETTLEMENT_BASE_INFO = "contract_settlement.base_info"
|
||||
"""
|
||||
id: str = Field(..., description="合同结算ID")
|
||||
contract_id: str = Field(..., description="所属合同ID", examples=["contract456"])
|
||||
show_name: Optional[str] = Field(None, description="合同简称", examples=["主变采购合同"])
|
||||
|
||||
class ContractSettlementPlanUpdate(BaseModel):
|
||||
"""
|
||||
合同结算计划节点更新模型
|
||||
CONTRACT_SETTLEMENT_PLAN_NODE = "contract_settlement.plan_node"
|
||||
|
||||
开始时间和金额在合同中维护,这里只维护计划节点和计划结束时间
|
||||
|
||||
业务逻辑说明:
|
||||
- API要求计划节点时间必须晚于计划开始时间(不能等于)
|
||||
- 自动清理脏数据:如果 plan_node 有2个或以上节点,删除边界节点
|
||||
"""
|
||||
id: str = Field(..., description="合同结算ID")
|
||||
plan_start_date: Optional[DateStr] = Field(None, exclude=True, description="计划开始时间(不推往后端,仅用于本地首节点清洗)", examples=["2024-06-30"])
|
||||
plan_complete_date: Optional[DateStr] = Field(None, description="计划结束时间", examples=["2024-06-30"])
|
||||
plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
|
||||
|
||||
@model_validator(mode='after')
|
||||
def clean_plan_nodes(self):
|
||||
"""
|
||||
清理计划节点列表中的边界节点
|
||||
|
||||
注:settlement的plan_start_date在contract中维护,此处利用外部提供的辅助字段清除非法首尾节点。
|
||||
"""
|
||||
if not self.plan_node or len(self.plan_node) < 2:
|
||||
return self
|
||||
|
||||
cleaned_nodes = list(self.plan_node)
|
||||
|
||||
# 删除开头的边界节点
|
||||
if (self.plan_start_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[0].date == self.plan_start_date):
|
||||
cleaned_nodes.pop(0)
|
||||
|
||||
# 删除结尾的边界节点
|
||||
if (self.plan_complete_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[-1].date == self.plan_complete_date):
|
||||
cleaned_nodes.pop()
|
||||
|
||||
self.plan_node = cleaned_nodes
|
||||
return self
|
||||
@@ -0,0 +1,128 @@
|
||||
from pydantic import Field, BaseModel,field_validator
|
||||
from fastapi import HTTPException
|
||||
from ..common.datetime import get_current_date
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.enums import ApprovalStatus
|
||||
from datetime import datetime
|
||||
|
||||
class ContractSettlementDetailResponse(BaseResponseWithID):
|
||||
"""
|
||||
合同结算明细返回模型
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属合同结算ID", examples=["settlement789"])
|
||||
date: DateStr = Field(..., description="结算日期", examples=["2024-05-31"])
|
||||
quantity: float = Field(..., description="合同金额", examples=[0])
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(None, description="是否完成", examples=[False])
|
||||
write_off_rate: Optional[float] = Field(None, description="核销率", examples=[0.0])
|
||||
change_count: int = Field(0, description="变更次数", examples=[0])
|
||||
status: Optional[int] = Field(None, description="进度状态", examples=[0])
|
||||
rate: Optional[float] = Field(None, description="实际完成率", examples=[0.0])
|
||||
|
||||
class ContractSettlementDetailCreate(BaseModel):
|
||||
"""
|
||||
合同结算明细创建模型
|
||||
CONTRACT_SETTLEMENT_DETAIL = "contract_settlement.detail"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属合同结算ID", examples=["settlement789"])
|
||||
date: DateStr = Field(..., description="结算日期", examples=["2024-05-31"])
|
||||
quantity: float = Field(..., description="合同金额", examples=[0])
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: bool = Field(False, description="是否完成", examples=[False])
|
||||
write_off_rate: Optional[float] = Field(None, description="核销率", examples=[0.0])
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='合同金额不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='结算日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class ContractSettlementDetailUpdate(BaseModel):
|
||||
"""
|
||||
合同结算明细更新模型
|
||||
CONTRACT_SETTLEMENT_DETAIL = "contract_settlement.detail"
|
||||
"""
|
||||
id: str = Field(..., description="合同明细ID")
|
||||
date: DateStr | None = Field(None, description="结算日期", examples=["2024-05-31"])
|
||||
quantity: float | None = Field(None, description="合同金额", examples=[0])
|
||||
remark: str | None = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: bool | None = Field(None, description="是否完成", examples=[False])
|
||||
write_off_rate: float | None = Field(None, description="核销率", examples=[0.0])
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus | None = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v is None:
|
||||
return None
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='合同金额不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v is None:
|
||||
return None
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='结算日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class ContractSettlementDetailBulkUpdate(BaseModel):
|
||||
detail_list: List[ContractSettlementDetailUpdate]
|
||||
@@ -0,0 +1,147 @@
|
||||
from pydantic import Field, BaseModel,field_validator,model_validator
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
class PlanNode(BaseModel):
|
||||
date: DateStr = Field(..., description="计划节点时间", examples=["2024-01-01"])
|
||||
quantity: float = Field(..., description="计划完成量", examples=[100.0])
|
||||
is_audit: Optional[bool] = Field(False, description="是否已审核", examples=[False])
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='计划完成量不能小于等于0')
|
||||
return v
|
||||
|
||||
class MaterialResponse(BaseResponseWithID):
|
||||
"""
|
||||
供货模型
|
||||
"""
|
||||
id : str = Field(..., description="物资ID", examples=["material123"])
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: str = Field("", description="所属合同ID", examples=["contract456"])
|
||||
show_name: str = Field("", description="展示名称", examples=["主变"])
|
||||
material_type: str = Field("", description="物资类型")
|
||||
contract_quantity: float = Field(0.0, description="合同数量", examples=[1000.0])
|
||||
plan_start_quantity: float = Field(
|
||||
0.0, description="计划首批到货量", examples=[1000.0]
|
||||
)
|
||||
complete_quantity: float = Field(0.0, description="实际到货累计", examples=[0.0])
|
||||
complete_rate: float = Field(0.0, description="实际到货率(%)", examples=[0.0])
|
||||
plan_start_date: Optional[DateStr] = Field(
|
||||
None, description="计划首批到货时间", examples=["2024-01-01"]
|
||||
)
|
||||
plan_complete_date: Optional[DateStr] = Field(
|
||||
None, description="计划全部到货时间", examples=["2024-06-01"]
|
||||
)
|
||||
actual_start_date: Optional[DateStr] = Field(
|
||||
None, description="实际首批到货时间", examples=["2024-01-15"]
|
||||
)
|
||||
actual_complete_date: Optional[DateStr] = Field(
|
||||
None, description="实际全部到货时间", examples=["2024-06-10"]
|
||||
)
|
||||
plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
|
||||
status: Optional[int] = Field(None, description="供货状态", examples=[0])
|
||||
|
||||
# 2025-10-20新增字段,延迟时间
|
||||
delay_days: Optional[int] = Field(None, description="延迟时间(天)", examples=[0])
|
||||
statistic_date: Optional[DateStr] = Field(
|
||||
None, description="统计节点截止日期", examples=["2024-05-31"]
|
||||
)
|
||||
|
||||
class MaterialCreate(BaseModel):
|
||||
"""
|
||||
创建物资
|
||||
MATERIAL_BASE_INFO = "material.base_info"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: str = Field(..., description="所属合同ID", examples=["contract456"])
|
||||
show_name: str = Field(..., description="展示名称", examples=["主变"])
|
||||
material_type: str = Field(..., description="物资类型")
|
||||
contract_quantity: float = Field(0.0, description="合同数量", examples=[1000.0])
|
||||
|
||||
@field_validator("contract_quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='合同数量不能小于0')
|
||||
return v
|
||||
|
||||
class MaterialUpdate(BaseModel):
|
||||
"""
|
||||
更新物资
|
||||
MATERIAL_BASE_INFO = "material.base_info"
|
||||
"""
|
||||
id: str = Field(..., description="物资ID", examples=["material123"])
|
||||
contract_id: Optional[str] = Field(None, description="所属合同ID", examples=["contract456"])
|
||||
show_name: Optional[str] = Field(None, description="展示名称", examples=["主变"])
|
||||
|
||||
|
||||
class MaterialPlanUpdate(BaseModel):
|
||||
"""
|
||||
物资计划更新模型
|
||||
MATERIAL_PLAN = "material.plan"
|
||||
|
||||
业务逻辑说明:
|
||||
- API要求计划节点时间必须晚于计划首批到货时间(不能等于)
|
||||
- 自动清理脏数据:如果 plan_node 有2个或以上节点,删除:
|
||||
1. 开头节点:如果其 date 等于 plan_start_date
|
||||
2. 结尾节点:如果其 date 等于 plan_complete_date
|
||||
- 这样避免提交包含边界节点的数据导致API报错
|
||||
"""
|
||||
id: str = Field(..., description="物资ID", examples=["material123"])
|
||||
plan_start_quantity: Optional[float] = Field(
|
||||
None, description="计划首批到货量", examples=[1000.0]
|
||||
)
|
||||
plan_start_date: Optional[str] = Field(None, description="计划首批到货时间", examples=["2024-01-01"])
|
||||
plan_complete_date: Optional[str] = Field(None, description="计划全部到货时间", examples=["2024-06-01"])
|
||||
contract_quantity: float = Field(..., description="合同数量", examples=[1000.0])
|
||||
plan_node: Optional[List[PlanNode]] = Field(default_factory=list, description="计划节点列表")
|
||||
|
||||
@field_validator("contract_quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='合同数量不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("plan_start_quantity")
|
||||
def validate_plan_start_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='计划首批到货量不能小于0')
|
||||
return v
|
||||
|
||||
@model_validator(mode='after')
|
||||
def clean_plan_nodes(self):
|
||||
"""
|
||||
清理计划节点列表中的边界节点
|
||||
|
||||
如果 plan_node 有2个或以上节点,删除:
|
||||
- 开头节点:date 等于 plan_start_date
|
||||
- 结尾节点:date 等于 plan_complete_date
|
||||
|
||||
这避免了API报错“计划节点时间必须晚于计划首批到货时间”
|
||||
"""
|
||||
if not self.plan_node or len(self.plan_node) < 2:
|
||||
return self
|
||||
|
||||
cleaned_nodes = list(self.plan_node)
|
||||
|
||||
# 删除开头的边界节点
|
||||
if (self.plan_start_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[0].date == self.plan_start_date):
|
||||
cleaned_nodes.pop(0)
|
||||
|
||||
# 删除结尾的边界节点
|
||||
if (self.plan_complete_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[-1].date == self.plan_complete_date):
|
||||
cleaned_nodes.pop()
|
||||
|
||||
self.plan_node = cleaned_nodes
|
||||
return self
|
||||
@@ -0,0 +1,132 @@
|
||||
from pydantic import Field, BaseModel,field_validator
|
||||
from fastapi import HTTPException
|
||||
from ..common.datetime import get_current_date
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.enums import ApprovalStatus
|
||||
from datetime import datetime
|
||||
|
||||
class MaterialDetailResponse(BaseResponseWithID):
|
||||
"""
|
||||
物资明细模型,存储在CouchDB中的物资明细文档
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属物资ID", examples=["material789"])
|
||||
date: DateStr = Field(..., description="实际到货日期", examples=["2024-05-31"])
|
||||
rate: Optional[float] = Field(None, description="实际到货率(%)", examples=[0.0])
|
||||
quantity: float = Field(0.0, ge=0, description="实际到货量累计", examples=[0.0])
|
||||
status: Optional[int] = Field(None, description="状态 0:正常 1:超前 -1:延误", examples=[0])
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部到货", examples=[False]
|
||||
)
|
||||
|
||||
class MaterialDetailCreate(BaseModel):
|
||||
"""
|
||||
物资明细创建模型
|
||||
MATERIAL_DETAIL = "material.detail"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属物资ID", examples=["material789"])
|
||||
quantity: float = Field(0.0, ge=0, description="实际到货量累计", examples=[0.0])
|
||||
date: DateStr = Field(..., description="实际到货日期", examples=["2024-05-31"])
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部到货", examples=[False]
|
||||
)
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='实际完成量累计不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='节点日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class MaterialDetailUpdate(BaseModel):
|
||||
"""
|
||||
物资明细更新模型
|
||||
MATERIAL_DETAIL = "material.detail"
|
||||
"""
|
||||
id: str = Field(..., description="物资明细ID")
|
||||
quantity: Optional[float] = Field(None, ge=0, description="实际到货量累计", examples=[0.0])
|
||||
date: Optional[DateStr] = Field(None, description="实际到货日期", examples=["2024-05-31"])
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部到货", examples=[False]
|
||||
)
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus | None = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v is None:
|
||||
return None
|
||||
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='实际完成量累计不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v is None:
|
||||
return None
|
||||
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='节点日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class MaterialDetailBulkUpdate(BaseModel):
|
||||
detail_list: List[MaterialDetailUpdate]
|
||||
@@ -0,0 +1,144 @@
|
||||
from pydantic import Field, BaseModel,field_validator,model_validator
|
||||
from fastapi import HTTPException
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
class PlanNode(BaseModel):
|
||||
date: DateStr = Field(..., description="计划节点时间", examples=["2024-01-01"])
|
||||
quantity: float = Field(..., description="计划完成量", examples=[100.0])
|
||||
is_audit: Optional[bool] = Field(False, description="是否已审核", examples=[False])
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证计划到场人数必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='计划节点人数不能小于0')
|
||||
return v
|
||||
|
||||
class PowerResponse(BaseResponseWithID):
|
||||
"""
|
||||
力能模型
|
||||
"""
|
||||
code: Optional[str] = Field(
|
||||
"personnel",
|
||||
description="力能类型(人员模块拓展为力能模块,可以在本字段保存人员/机具等编码)",
|
||||
examples=["personnel"],
|
||||
)
|
||||
project_id: str = Field(..., description="所属项目", examples=["project123"])
|
||||
contract_id: Optional[str] = Field(
|
||||
None,
|
||||
description="所属合同(目前前端页面显示没有按这个字段,仅通过脚本绑定了epc合同,用于接口数据推送。后续行为待讨论)",
|
||||
examples=["contract456"],
|
||||
)
|
||||
show_name: str = Field("", description="展示名称", examples=["施工班组A"])
|
||||
status: Optional[int] = Field(None, description="人员状态", examples=[0])
|
||||
plan_attendance: int = Field(
|
||||
0,
|
||||
description="计划出勤人数(暂时定为最后一次报明细时的计划出勤人数)",
|
||||
examples=[10],
|
||||
)
|
||||
actual_daily_attendance: int = Field(0, description="实际日均出勤", examples=[8])
|
||||
attendance_rate: float = Field(0.0, description="出勤率", examples=[0.8])
|
||||
statistic_date: Optional[DateStr] = Field(
|
||||
None, description="统计节点", examples=["2024-05-31"]
|
||||
)
|
||||
plan_exit_date: Optional[DateStr] = Field(
|
||||
None, description="计划退场时间", examples=["2024-06-30"]
|
||||
)
|
||||
actual_exit_date: Optional[DateStr] = Field(
|
||||
None, description="实际退场时间", examples=["2024-07-05"]
|
||||
)
|
||||
plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
|
||||
plan_start_date: Optional[DateStr] = Field(
|
||||
None, description="计划首批到场时间", examples=["2024-05-01"]
|
||||
)
|
||||
plan_start_quantity: int = Field(0, description="计划首批到场人数", examples=[5], ge=0)
|
||||
actual_start_date: Optional[DateStr] = Field(
|
||||
None, description="实际首批到场时间", examples=["2024-05-02"]
|
||||
)
|
||||
actual_start_quantity: Optional[int] = Field(
|
||||
None, description="实际首批到场人数", examples=[4]
|
||||
)
|
||||
|
||||
class PowerCreate(BaseModel):
|
||||
"""
|
||||
创建力能
|
||||
POWER_BASE_INFO = "personnel.base_info"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目ID", examples=["project123"])
|
||||
contract_id: Optional[str] = Field(
|
||||
None, description="所属合同ID", examples=["contract456"]
|
||||
)
|
||||
#show_name: str = Field(..., description="展示名称", examples=["施工班组A"])
|
||||
code: Optional[str] = Field(
|
||||
"personnel",
|
||||
description="力能类型(人员模块拓展为力能模块,可以在本字段保存人员/机具等编码)",
|
||||
examples=["personnel"],
|
||||
)
|
||||
|
||||
class PowerUpdate(BaseModel):
|
||||
"""
|
||||
更新力能
|
||||
POWER_BASE_INFO = "personnel.base_info"
|
||||
"""
|
||||
id: str = Field(..., description="力能ID")
|
||||
contract_id: Optional[str] = Field(
|
||||
None, description="所属合同ID", examples=["contract456"]
|
||||
)
|
||||
#show_name: Optional[str] = Field(None, description="展示名称", examples=["施工班组A"])
|
||||
|
||||
class PowerPlanUpdate(BaseModel):
|
||||
"""
|
||||
力能计划更新模型
|
||||
POWER_PLAN = "personnel.plan"
|
||||
|
||||
业务逻辑说明:
|
||||
- API要求计划节点时间必须晚于计划首批到场时间(不能等于)
|
||||
- 自动清理脏数据:如果 plan_node 有2个或以上节点,删除边界节点
|
||||
"""
|
||||
id: str = Field(..., description="力能ID")
|
||||
plan_start_date: str = Field(..., description="计划首批到场时间")
|
||||
plan_start_quantity: int = Field(..., description="计划首批到场人数")
|
||||
plan_exit_date: DateStr = Field(
|
||||
..., description="计划退场时间", examples=["2024-06-30"]
|
||||
)
|
||||
plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
|
||||
|
||||
@field_validator("plan_start_quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证计划首批到场人数必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='计划首批进场人数必须大于等于0')
|
||||
return v
|
||||
|
||||
@model_validator(mode='after')
|
||||
def clean_plan_nodes(self):
|
||||
"""
|
||||
清理计划节点列表中的边界节点
|
||||
|
||||
如果 plan_node 有2个或以上节点,删除:
|
||||
- 开头节点:date 等于 plan_start_date
|
||||
- 结尾节点:date 等于 plan_exit_date
|
||||
|
||||
这避免了API报错“计划节点时间必须晚于计划首批到场时间”
|
||||
"""
|
||||
if not self.plan_node or len(self.plan_node) < 2:
|
||||
return self
|
||||
|
||||
cleaned_nodes = list(self.plan_node)
|
||||
|
||||
# 删除开头的边界节点
|
||||
if (self.plan_start_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[0].date == self.plan_start_date):
|
||||
cleaned_nodes.pop(0)
|
||||
|
||||
# 删除结尾的边界节点
|
||||
if (self.plan_exit_date and
|
||||
cleaned_nodes and
|
||||
cleaned_nodes[-1].date == self.plan_exit_date):
|
||||
cleaned_nodes.pop()
|
||||
|
||||
self.plan_node = cleaned_nodes
|
||||
return self
|
||||
@@ -0,0 +1,133 @@
|
||||
from pydantic import Field, BaseModel,field_validator
|
||||
from fastapi import HTTPException
|
||||
from ..common.datetime import get_current_date
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.enums import ApprovalStatus
|
||||
from datetime import datetime
|
||||
|
||||
class PowerDetail(BaseResponseWithID):
|
||||
"""
|
||||
力能配置明细
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属力能配置ID", examples=["personnel789"])
|
||||
date: DateStr = Field(..., description="本次日期", examples=["2024-05-31"])
|
||||
quantity: int = Field(..., description="累计完成量", examples=[0], ge=0)
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部退场", examples=[False]
|
||||
)
|
||||
change_count: int = Field(0, description="变更次数", examples=[0])
|
||||
status: Optional[int] = Field(None, description="进度状态", examples=[0])
|
||||
rate: Optional[float] = Field(None, description="出勤率", examples=[0])
|
||||
|
||||
class PowerDetailCreate(BaseModel):
|
||||
"""
|
||||
力能配置明细创建模型
|
||||
POWER_DETAIL = "power.detail"
|
||||
"""
|
||||
project_id: str = Field(..., description="所属项目", examples=["project123"])
|
||||
parent_id: str = Field(..., description="所属力能配置ID", examples=["personnel789"])
|
||||
date: DateStr = Field(..., description="本次日期", examples=["2024-05-31"])
|
||||
quantity: int = Field(..., description="累计完成量", examples=[0], ge=0)
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部退场", examples=[False]
|
||||
)
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='实际完成量累计不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='节点日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class PowerDetailUpdate(BaseModel):
|
||||
"""
|
||||
力能配置明细更新模型
|
||||
POWER_DETAIL = "power.detail"
|
||||
"""
|
||||
id: str = Field(..., description="力能配置明细ID")
|
||||
date: Optional[DateStr] = Field(None, description="本次日期", examples=["2024-05-31"])
|
||||
quantity: Optional[int] = Field(None, description="累计完成量", examples=[0], ge=0)
|
||||
remark: Optional[str] = Field(None, description="填报备注", examples=[""])
|
||||
is_complete: Optional[bool] = Field(
|
||||
None, description="是否为全部退场", examples=[False]
|
||||
)
|
||||
confirmation_time: str | None = Field(None, description="确认时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_time: str | None = Field(None, description="审批时间", examples=["2025-12-17 11:13:49"])
|
||||
approval_status: ApprovalStatus | None = Field("registered", description="审批状态", examples=["registered"])
|
||||
|
||||
@field_validator("approval_status")
|
||||
def validate_approval_status(cls, v):
|
||||
"""验证审批字段"""
|
||||
if v is None:
|
||||
return v
|
||||
try:
|
||||
return ApprovalStatus(v) # 尝试转换
|
||||
except ValueError:
|
||||
raise HTTPException(400, f"审批状态 '{v}' 无效")
|
||||
|
||||
@field_validator("confirmation_time", "approval_time")
|
||||
def validate_time(cls, v):
|
||||
"""验证时间"""
|
||||
if v is None:
|
||||
return v
|
||||
|
||||
try:
|
||||
datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError:
|
||||
raise HTTPException(detail=f'{v}时间格式错误,应为:2025-12-17 11:13:49', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("quantity")
|
||||
def validate_quantity(cls, v):
|
||||
"""验证实际完成量累计必须为非负数"""
|
||||
if v is None:
|
||||
return None
|
||||
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail='实际完成量累计不能小于0')
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v is None:
|
||||
return None
|
||||
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='节点日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class PowerDetailBulkUpdate(BaseModel):
|
||||
detail_list: List[PowerDetailUpdate]
|
||||
@@ -0,0 +1,30 @@
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class ProgressType(str, Enum):
|
||||
"""推进分类枚举"""
|
||||
A = "A"
|
||||
B = "B"
|
||||
C = "C"
|
||||
|
||||
class KeyConstraints(str, Enum):
|
||||
NONE = "NONE"
|
||||
LAND = "LAND"
|
||||
TRANSMISSION = "TRANSMISSION"
|
||||
BOTH = "BOTH"
|
||||
QT = "QT"
|
||||
|
||||
class DBTCSCORE(BaseModel):
|
||||
year: str = Field(..., description="评分年份, yyyy格式")
|
||||
is_jg: bool = Field(..., description="是否为工达标投产")
|
||||
score: float = Field(..., description="集团考核评分")
|
||||
|
||||
class ProjectType(str, Enum):
|
||||
"""项目类型枚举"""
|
||||
PHOTOVOLTAIC = "photovoltaic" # 光伏
|
||||
OFFSHORE_WIND = "offshore_wind" # 海风
|
||||
ONSHORE_WIND = "onshore_wind" # 陆风
|
||||
HYDROPOWER = "hydropower" # 水电
|
||||
THERMAL_POWER = "thermal_power" # 火电
|
||||
PUMPED_STORAGE = "pumped_storage" # 抽蓄
|
||||
GAS_TURBINE = "gas_turbine" # 气电
|
||||
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
项目全部信息的增删查改模板,聚合了项目相关schema
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field, field_serializer
|
||||
from typing import Optional
|
||||
from .project_base import (
|
||||
ProjectResponseBase,
|
||||
ProjectEnsureCapacity,
|
||||
ProjectClimbCapacity,
|
||||
ProjectChallengeCapacity,
|
||||
ProjectActualConstruction,
|
||||
ProjectPlanConstruction,
|
||||
ProjectInvestmentDecision,
|
||||
ProjectKeyConstraints,
|
||||
ProjectProductionCapacity,
|
||||
ProjectCompleteInvestment,
|
||||
ProjectDynamicInvestment
|
||||
)
|
||||
from ..project_extensions.preparation import PreparationDetail
|
||||
from ..project_extensions.production import ProductionDetail
|
||||
from ..project_extensions.project_detail import ProjectDetailProject
|
||||
from ..project_extensions.generator_unit import (
|
||||
GeneratorUnitProject,
|
||||
PostGeneratorUnits
|
||||
)
|
||||
from ..project_extensions.lar import (
|
||||
LarDetailSchema,
|
||||
LarChangeListSchema,
|
||||
LarChangeUpdateSchema,
|
||||
LarMainInfoUpdateSchema,
|
||||
LarResettlementSchema,
|
||||
LarInvestmentSchema, LarChangeDetailSchema
|
||||
)
|
||||
from ..project_extensions.contract_change import (
|
||||
ContractChangeResponse,
|
||||
PostContractChange
|
||||
)
|
||||
|
||||
from ..project_multi_type import (
|
||||
PhotovoltaicExtension,
|
||||
OnShoreWindExtension,
|
||||
OffShoreWindExtension,
|
||||
HydropowerExtension,
|
||||
PumpedStorageExtension,
|
||||
GasTurbineExtension,
|
||||
ThermalPowerExtension
|
||||
)
|
||||
|
||||
|
||||
class ProjectInfoResponse(BaseModel):
|
||||
"""
|
||||
项目全部信息响应模型
|
||||
"""
|
||||
|
||||
project: ProjectResponseBase = Field(..., description="项目基本信息")
|
||||
project_detail: list[ProjectDetailProject] = Field(..., description="项目容量信息")
|
||||
generator_units: list[GeneratorUnitProject] = Field(..., description="发电单元信息列表(仅限水电、抽蓄、煤电、气电)")
|
||||
lar: Optional[LarDetailSchema] = Field(None, description="移民征地信息(仅限水电、抽蓄)")
|
||||
lar_change: list[LarChangeDetailSchema] = Field(default_factory=list, description="移民变更信息列表(仅限水电、抽蓄)")
|
||||
contract_changes: list[ContractChangeResponse] = Field(..., description="合同变更信息列表(仅限水电、抽蓄、煤电、气电)")
|
||||
|
||||
# 扩展字段
|
||||
photovoltaic_extension: PhotovoltaicExtension | None = Field(None, description="光伏项目扩展信息")
|
||||
onshore_wind_extension: OnShoreWindExtension | None = Field(None, description="陆风项目扩展信息")
|
||||
offshore_wind_extension: OffShoreWindExtension | None = Field(None, description="海风项目扩展信息")
|
||||
hydropower_extension: HydropowerExtension | None = Field(None, description="水电项目扩展信息")
|
||||
pumped_storage_extension: PumpedStorageExtension | None = Field(None, description="抽蓄项目扩展信息")
|
||||
gas_turbine_extension: GasTurbineExtension | None = Field(None, description="燃气轮机项目扩展信息")
|
||||
thermal_power_extension: ThermalPowerExtension | None = Field(None, description="火电项目扩展信息")
|
||||
|
||||
# 投产节点
|
||||
production_list: list[ProductionDetail] = Field(default_factory=list, description="投产节点列表")
|
||||
# 里程碑节点
|
||||
preparation_list: list[PreparationDetail] = Field(default_factory=list, description="里程碑节点列表")
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
"""
|
||||
项目数据推送相关schema
|
||||
"""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import HTTPException
|
||||
from pydantic import Field, BaseModel, field_validator
|
||||
from ..common.push_system import BaseUpdateRequestSchema
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.datetime import get_current_date
|
||||
from ..common.validators import DateStr
|
||||
from .enums import ProgressType, KeyConstraints, DBTCSCORE
|
||||
|
||||
class ProjectResponseBase(BaseResponseWithID):
|
||||
"""
|
||||
项目基础信息, 复制自project_model
|
||||
不进行继承,通过检查器确保字段和模型一致
|
||||
"""
|
||||
# 基础信息-不允许更改
|
||||
id : str = Field(..., description="项目ID", examples=["uuid"])
|
||||
project_type: str = Field("", description="项目类型")
|
||||
region_name: List[str] = Field(default_factory=list, description="项目所属区域名称", examples=[["华东", "江苏"]])
|
||||
region_path: List[str] = Field(default_factory=list, description="项目所属区域路径", examples=[["110000", "120000", "120001"]])
|
||||
province: str = Field("", description="省份(region_path第一个)", examples=["110000"])
|
||||
is_domestic :bool=Field(True, description="是否是国内项目")
|
||||
company_id: str = Field("", description="所属公司ID", examples=["company123"])
|
||||
company_name: str = Field("", description="所属公司名称", examples=["国电投江苏公司"])
|
||||
syxs: Optional[str] = Field(None, description="升压站型式")
|
||||
sub_type: Optional[str] = Field(None, description="光伏类别")
|
||||
scgc_type: Optional[str] = Field(None, description="送出工程建设方式")
|
||||
|
||||
# 基础信息-允许更改
|
||||
address: str = Field("", description="项目地址", examples=["某省某市某区"])
|
||||
code: str = Field("", description="项目编码", examples=["XM2025001"])
|
||||
name: str = Field(..., description="项目名称", examples=["XX新能源项目"])
|
||||
short_name: str = Field("", description="项目简称", examples=["XX项目"])
|
||||
manager_name: str = Field("", description="负责人姓名", examples=["张三"])
|
||||
manager_phone: str = Field("", description="负责人电话", examples=["13800000000"])
|
||||
|
||||
|
||||
# 容量信息
|
||||
authorization_date: Optional[DateStr] = Field(None, description="核准日期", examples=["2024-01-01"])
|
||||
authorized_capacity: float = Field(0.0, description="核准容量(万千瓦)", examples=[10.0])
|
||||
# 投决
|
||||
investment_decision_capacity: Optional[float] = Field(None, description="投资决策容量", examples=[8.0])
|
||||
investment_decision_date: Optional[DateStr] = Field(None, description="投资决策日期", examples=["2024-02-01"])
|
||||
# 开工
|
||||
plan_construction_capacity: float = Field(0.0, description="本年度计划开工容量", examples=[5.0])
|
||||
plan_construction_date: Optional[DateStr] = Field(None, description="本年度计划开工日期", examples=["2024-03-01"])
|
||||
actual_construction_capacity: float = Field(0.0, description="本年度实际开工容量", examples=[4.0])
|
||||
actual_construction_date: Optional[DateStr] = Field(None, description="本年度实际开工日期", examples=["2024-04-01"])
|
||||
accumulated_construction_capacity: float = Field(0.0, description="累计开工容量", examples=[12.0])
|
||||
constructing_capacity: float = Field(0.0, description="在建容量", examples=[6.0])
|
||||
|
||||
# 投产
|
||||
ensure_production_capacity: float = Field(0.0, description="本年度确保投产容量", examples=[3.0])
|
||||
challenge_production_capacity: float = Field(0.0, description="本年度揭榜投产容量", examples=[2.0])
|
||||
climb_production_capacity: float = Field(0.0, description="本年度登高投产容量", examples=[1.0])
|
||||
plan_production_date: Optional[DateStr] = Field(None, description="计划投产日期", examples=["2024-08-01"])
|
||||
plan_full_production_date: Optional[DateStr] = Field(None, description="计划全部投产日期", examples=["2024-09-01"])
|
||||
actual_production_date: Optional[DateStr] = Field(None, description="实际投产日期", examples=["2024-08-15"])
|
||||
actual_full_production_date: Optional[DateStr] = Field(None, description="实际全投日期", examples=["2024-09-10"])
|
||||
production_capacity: Optional[float] = Field(0.0, description="本年度投产容量", examples=[2.0])
|
||||
production_date: Optional[DateStr] = Field(None, description="本年度首批投产日期", examples=["2024-09-01"])
|
||||
total_production_capacity: Optional[float] = Field(0.0, description="全部投产容量", examples=[2.0])
|
||||
|
||||
# 投资
|
||||
dynamic_investment: float = Field(0.0, description="动态总投资", examples=[100000.0])
|
||||
complete_investment: float = Field(0.0, description="完成投资", examples=[80000.0])
|
||||
|
||||
# 其他信息
|
||||
progress_type: ProgressType = Field(..., description="推进分类", examples=[ProgressType.A])
|
||||
key_constraints: KeyConstraints = Field(KeyConstraints.NONE, description="关键制约", examples=[KeyConstraints.NONE])
|
||||
key_constraints_remark: Optional[str] = Field("", description="关键制约备注", examples=["无"])
|
||||
status: Optional[str] = Field(None, description="项目状态")
|
||||
apply_file_ids: List[str] = Field(default_factory=list, description="申请表附件ID列表", examples=[[]])
|
||||
|
||||
# 拓展信息
|
||||
dbtc_score_list: Optional[list] = Field(default_factory=list, description='达标投产评分列表') # 这里项目用的是list而不是List
|
||||
|
||||
|
||||
|
||||
class ProjectResponseBaseList(BaseModel):
|
||||
page: int
|
||||
page_size: int
|
||||
total: int
|
||||
list: List[ProjectResponseBase] = []
|
||||
|
||||
|
||||
|
||||
|
||||
# ==================== Update ====================
|
||||
|
||||
class KeyConstraintsRemarkMixin:
|
||||
"""关键制约备注校验混入类"""
|
||||
|
||||
@field_validator("key_constraints_remark")
|
||||
def validate_key_constraints_remark(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
if len(v) > 500:
|
||||
raise HTTPException(detail="关键制约备注不能超过500个字符", status_code=400)
|
||||
return v
|
||||
|
||||
class AuthorizationDateMixin:
|
||||
"""关键制约备注校验混入类"""
|
||||
|
||||
@field_validator("authorization_date")
|
||||
def validate_actual_date(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='核准/备案日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class ProjectBaseInfoUpdate(BaseModel, KeyConstraintsRemarkMixin, AuthorizationDateMixin):
|
||||
"""
|
||||
项目基本信息 PROJECT_BASE_INFO
|
||||
"""
|
||||
# 基础信息-允许更改
|
||||
id: str = Field(..., description="项目id", examples=["uuid"])
|
||||
address: str | None = Field(None, description="项目地址", examples=["某省某市某区"])
|
||||
code: str | None = Field(None, description="项目编码", examples=["XM2025001"])
|
||||
name: str = Field(..., description="项目名称", examples=["XX新能源项目"])
|
||||
short_name: str | None = Field(None, description="项目简称", examples=["XX项目"])
|
||||
manager_name: str | None = Field(None, description="负责人姓名", examples=["张三"])
|
||||
manager_phone: str | None = Field(None, description="负责人电话", examples=["13800000000"])
|
||||
# 其他信息
|
||||
progress_type: ProgressType = Field(..., description="推进分类", examples=[ProgressType.A])
|
||||
key_constraints: KeyConstraints | None = Field(None, description="关键制约", examples=[KeyConstraints.NONE])
|
||||
key_constraints_remark: str | None = Field(None, description="关键制约备注", examples=["无"])
|
||||
apply_file_ids: List[str] | None = Field(None, description="申请表附件ID列表", examples=[[]])
|
||||
# 拓展信息
|
||||
dbtc_score_list: list[DBTCSCORE] | None = Field(None, description='达标投产评分列表') # 这里项目用的是list而不是List
|
||||
|
||||
# 核准
|
||||
authorization_date: DateStr | None = Field(None, description="核准日期", examples=["2024-01-01"])
|
||||
authorized_capacity: float | None = Field(None, description="核准容量(万千瓦)", examples=[10.0])
|
||||
|
||||
|
||||
|
||||
class _ProductionPlanNode(BaseModel):
|
||||
year: int = Field(..., description="计划年份", examples=[2024])
|
||||
capacity: float = Field(..., description="确保投产容量", examples=[3.0])
|
||||
|
||||
class ProjectEnsureCapacity(BaseModel):
|
||||
"""
|
||||
PROJECT_ENSURE_CAPACITY
|
||||
填写项目确保投产容量列表,系统根据列表自动计算ensure_production_capacity字段
|
||||
"""
|
||||
# 确保投产容量
|
||||
ensure_production_capacity_list : list[_ProductionPlanNode] = Field(..., description="确保投产容量列表(每次必须填写全部)")
|
||||
|
||||
class ProjectClimbCapacity(BaseModel):
|
||||
"""
|
||||
PROJECT_CLIMB_CAPACITY
|
||||
填写项目登高投产容量列表,系统根据列表自动计算climb_production_capacity字段
|
||||
"""
|
||||
# 登高投产容量
|
||||
climb_production_capacity_list : list[_ProductionPlanNode] = Field(..., description="登高投产容量列表(每次必须填写全部)")
|
||||
class ProjectChallengeCapacity(BaseModel):
|
||||
"""
|
||||
PROJECT_CHALLENGE_CAPACITY
|
||||
填写项目揭榜投产容量列表,系统根据列表自动计算challenge_production_capacity字段
|
||||
"""
|
||||
# 揭榜投产容量
|
||||
challenge_production_capacity_list : list[_ProductionPlanNode] = Field(..., description="揭榜投产容量列表(每次必须填写全部)")
|
||||
|
||||
|
||||
|
||||
class _ActualNodeData(BaseModel):
|
||||
capacity: float = Field(..., description="实际节点容量", examples=[4.0])
|
||||
date: DateStr = Field(..., description="实际节点日期", examples=["2024-04-01"])
|
||||
class ProjectActualConstruction(BaseModel):
|
||||
"""
|
||||
PROJECT_ACTUAL_CONSTRUCTION
|
||||
项目实际开工节点
|
||||
|
||||
系统根据实际开工节点自动计算以下字段:
|
||||
actual_construction_capacity 本年度实际开工容量
|
||||
actual_construction_date 本年度实际开工日期
|
||||
accumulated_construction_capacity 累计开工容量
|
||||
constructing_capacity 在建容量
|
||||
"""
|
||||
actual_construction_list : list[_ActualNodeData] | None = Field(None, description="实际开工节点列表(每次必须填写全部)")
|
||||
|
||||
class _PlanNodeData(BaseModel):
|
||||
capacity: float = Field(..., description="计划节点容量", examples=[5.0])
|
||||
date: DateStr = Field(..., description="本年度计日期", examples=["2024-03-01"])
|
||||
|
||||
@field_validator("capacity")
|
||||
def validate_capacity(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="节点容量必须大于等于0")
|
||||
return v
|
||||
|
||||
class ProjectPlanConstruction(BaseModel):
|
||||
"""
|
||||
PROJECT_PLAN_CONSTRUCTION
|
||||
项目计划开工节点
|
||||
|
||||
系统根据计划开工节点自动计算:
|
||||
plan_construction_capacity 本年度计划开工容量
|
||||
plan_construction_date 本年度计划开工日期
|
||||
"""
|
||||
plan_construction_list : list[_PlanNodeData] | None = Field(None, description="计划开工节点列表(每次必须填写全部)")
|
||||
|
||||
class ProjectInvestmentDecision(BaseModel):
|
||||
"""
|
||||
PROJECT_INVESTMENT_DECISION
|
||||
投资决策容量和日期
|
||||
"""
|
||||
investment_decision_capacity: float = Field(..., description="投资决策容量", examples=[8.0])
|
||||
investment_decision_date: DateStr = Field(..., description="投资决策日期", examples=["2024-02-01"])
|
||||
|
||||
@field_validator("investment_decision_date")
|
||||
def validate_investment_decision_date(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='投资决策日期不能大于今天', status_code=400)
|
||||
return v
|
||||
@field_validator("investment_decision_capacity")
|
||||
def validate_investment_decision_capacity(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="投资决策容量必须大于等于0")
|
||||
return v
|
||||
|
||||
class ProjectKeyConstraints(BaseModel, KeyConstraintsRemarkMixin):
|
||||
"""
|
||||
PROJECT_KEY_CONSTRAINTS
|
||||
关键制约
|
||||
"""
|
||||
key_constraints: KeyConstraints | None = Field(None, description="关键制约", examples=[KeyConstraints.NONE])
|
||||
key_constraints_remark: str | None = Field(None, description="关键制约备注", examples=["无"])
|
||||
|
||||
class _ActualProductionNode(BaseModel):
|
||||
capacity: float = Field(..., description="实际投产容量", examples=[2.0])
|
||||
date: DateStr = Field(..., description="实际投产日期", examples=["2024-08-15"])
|
||||
|
||||
@field_validator("capacity")
|
||||
def validate_capacity(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="实际投产容量必须大于等于0")
|
||||
return v
|
||||
|
||||
@field_validator("date")
|
||||
def validate_date(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='实际投产日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class ProjectProductionCapacity(BaseModel):
|
||||
"""
|
||||
PROJECT_PRODUCTION_CAPACITY
|
||||
填写项目投产数据
|
||||
每个项目在各年份或一年内可能有多次实际投产
|
||||
系统会根据投产节点列表数据,自动计算
|
||||
production_capacity 本年度投产容量
|
||||
production_date 本年度首批投产日期
|
||||
total_production_capacity 全部投产容量
|
||||
"""
|
||||
plan_production_date: DateStr | None = Field(None, description="集团公司计划投产日期", examples=["2024-08-01"])
|
||||
plan_full_production_date: DateStr | None = Field(None, description="集团公司计划全部投产日期", examples=["2024-09-01"])
|
||||
ic_plan_first_production_date: DateStr | None = Field(None, description="区域公司计划首批投产日期(只有新能源需要)",examples=["2024-08-01"])
|
||||
ic_plan_full_production_date: DateStr | None = Field(None, description="区域公司计划全投日期(只有新能源需要)",examples=["2024-09-01"])
|
||||
actual_production_date: DateStr | None = Field(None, description="实际投产日期(只有新能源需要)", examples=["2024-08-15"])
|
||||
actual_full_production_date: DateStr | None = Field(None, description="实际全投日期(只有新能源需要)", examples=["2024-09-10"])
|
||||
actual_production_list : list[_ActualProductionNode] | None = Field(None, description="实际投产节点列表(每次必须填写全部)(只有新能源需要)")
|
||||
@field_validator("actual_production_date")
|
||||
def validate_actual_production_date(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='实际投产日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator("actual_full_production_date")
|
||||
def validate_actual_full_production_date(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='实际全投日期不能大于今天', status_code=400)
|
||||
return v
|
||||
|
||||
class ProjectCompleteInvestment(BaseModel):
|
||||
"""
|
||||
PROJECT_COMPLETE_INVESTMENT
|
||||
完成投资投资
|
||||
"""
|
||||
|
||||
complete_investment: float = Field(..., description="完成投资", examples=[80000.0])
|
||||
|
||||
@field_validator("complete_investment")
|
||||
def validate_complete_investment(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400,detail="完成投资必须大于等于0")
|
||||
return v
|
||||
|
||||
class ProjectSettlementInvestment(BaseModel):
|
||||
"""
|
||||
PROJECT_SETTLEMENT_INVESTMENT
|
||||
合同结算投资情况
|
||||
"""
|
||||
|
||||
implementation_estimate: float = Field(..., description="执行概算", examples=[80000.0])
|
||||
static_total_investment: float = Field(..., description="静态总投资", examples=[80000.0])
|
||||
completed_investment: float = Field(..., description="完成投资", examples=[80000.0])
|
||||
dynamic_investment: float = Field(..., description="动态总投资", examples=[80000.0])
|
||||
|
||||
@field_validator("implementation_estimate")
|
||||
def validate_implementation_estimate(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400,detail="执行概算必须大于等于0")
|
||||
return v
|
||||
|
||||
@field_validator("static_total_investment")
|
||||
def validate_static_total_investment(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="静态总投资必须大于等于0")
|
||||
return v
|
||||
|
||||
@field_validator("completed_investment")
|
||||
def validate_completed_investment(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="完成投资必须大于等于0")
|
||||
return v
|
||||
|
||||
@field_validator("dynamic_investment")
|
||||
def validate_dynamic_investment(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="动态总投资必须大于等于0")
|
||||
return v
|
||||
|
||||
class ProjectDynamicInvestment(BaseModel):
|
||||
"""
|
||||
PROJECT_DYNAMIC_INVESTMENT
|
||||
"""
|
||||
# 动态总投资
|
||||
dynamic_investment: float | None = Field(None, description="动态总投资", examples=[100000.0])
|
||||
|
||||
@field_validator("dynamic_investment")
|
||||
def validate_dynamic_investment(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="动态总投资必须大于等于0")
|
||||
return v
|
||||
|
||||
# ======================= 水电抽蓄专用 =============================
|
||||
|
||||
|
||||
# ==================== 枚举说明 用于文档自动生成 ====================
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
contract_change相关schemea
|
||||
"""
|
||||
from ..common.validators import DateStr
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from ..common.base import BaseResponseWithID
|
||||
from pydantic import field_validator
|
||||
from fastapi import HTTPException
|
||||
|
||||
class ContractChangeResponse(BaseResponseWithID):
|
||||
"""
|
||||
合同变更模型
|
||||
"""
|
||||
id: Optional[str] = Field(default=None, description="合同变更ID")
|
||||
project_id : Optional[str] = Field(None, description="所属项目ID")
|
||||
contract_id: Optional[str] = Field(None, description="关联合同ID")
|
||||
name: Optional[str] = Field(None, description="合同名称")
|
||||
sub_name: Optional[str] = Field(None, description="合同子标题(epc合同和pc合同会有子标题)")
|
||||
sign_company:Optional[str] = Field(None, description="签约公司")
|
||||
title: Optional[str] = Field(None, description="变更事项")
|
||||
reason: Optional[str] = Field(None, description="变更理由")
|
||||
before_amount: Optional[float] = Field(None, description="变更前金额")
|
||||
after_amount: Optional[float] = Field(None, description="变更后金额")
|
||||
change_count: Optional[float] = Field(None, description="变更金额")
|
||||
change_rate: Optional[str] = Field(None, description="变更比例")
|
||||
change_time: Optional[str] = Field(None, description="变更时间(格式:YYYY-MM-DD)")
|
||||
attachment_ids:Optional[list] = Field(None, description="附件ID列表")
|
||||
attachment_names:Optional[list] = Field(None, description="附件名称列表")
|
||||
created_at:Optional[str]=Field(None, description="创建时间")
|
||||
created_by_name: Optional[str] = Field(None, description="创建人名称")
|
||||
|
||||
class PostContractChange(BaseModel):
|
||||
"""
|
||||
合同变更请求(水火抽蓄气电)
|
||||
PROJECT_CONTRACT_CHANGE = "project.contract-change"
|
||||
"""
|
||||
|
||||
|
||||
id: str = Field(..., description="合同变更ID,更新时传入,创建时不传")
|
||||
project_id: str = Field(..., description="所属项目ID")
|
||||
contract_id: str = Field(..., description="合同ID")
|
||||
title: str = Field(..., description="变更事项")
|
||||
reason: str = Field(..., description="变更理由")
|
||||
before_amount: float = Field(..., description="变更前金额")
|
||||
after_amount: float = Field(..., description="变更后金额")
|
||||
change_time: DateStr = Field(..., description="变更时间(格式:YYYY-MM-DD)")
|
||||
attachment_ids: list = Field(..., description="附件ID列表")
|
||||
|
||||
@field_validator("after_amount")
|
||||
def validate_after_amount(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="变更后金额必须小于等于0")
|
||||
return v
|
||||
|
||||
class CreateContractChange(BaseModel):
|
||||
"""
|
||||
创建合同变更请求(水火抽蓄气电)
|
||||
PROJECT_CONTRACT_CHANGE = "project.contract-change"
|
||||
"""
|
||||
|
||||
project_id: str = Field(..., description="所属项目ID")
|
||||
contract_id: str = Field(..., description="合同ID")
|
||||
title: str = Field(..., description="变更事项")
|
||||
reason: str = Field(..., description="变更理由")
|
||||
before_amount: float = Field(..., description="变更前金额")
|
||||
after_amount: float = Field(..., description="变更后金额")
|
||||
change_time: DateStr = Field(..., description="变更时间(格式:YYYY-MM-DD)")
|
||||
attachment_ids: list = Field(..., description="附件ID列表")
|
||||
|
||||
@field_validator("after_amount")
|
||||
def validate_after_amount(cls, v: float) -> float:
|
||||
if v < 0:
|
||||
raise HTTPException(status_code=400, detail="变更后金额不能小于0")
|
||||
return v
|
||||
@@ -0,0 +1,34 @@
|
||||
from pydantic import BaseModel, Field,field_validator
|
||||
from typing import Optional
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.datetime import datetime_date,get_current_date
|
||||
from fastapi import HTTPException
|
||||
|
||||
class GeneratorUnitProject(BaseResponseWithID):
|
||||
project_id : Optional[str]= Field(None, description="项目ID")
|
||||
serial_number: Optional[int] = Field(None, description="机组序号")
|
||||
approval_status:Optional[str]=Field(None, description="审批状态")
|
||||
capacity: Optional[float] = Field(None, description="单机容量(MW)")
|
||||
plan_production_date: Optional[str] = Field(None, description="计划投产日期")
|
||||
actual_production_date: Optional[str] = Field(None, description="实际投产日期")
|
||||
|
||||
class PostGeneratorUnits(BaseModel):
|
||||
model_config = {"populate_by_name": True}
|
||||
|
||||
id:str = Field(..., description="机组ID")
|
||||
project_id: str = Field(..., description="所属项目ID")
|
||||
actual_production_date: str = Field(..., alias="actual_date", description="实际投产日期(格式:YYYY-MM-DD)")
|
||||
|
||||
@field_validator('actual_production_date', mode="before")
|
||||
def validate_actual_date_not_future(cls, v: str) -> str:
|
||||
if v == "":
|
||||
return ""
|
||||
try:
|
||||
actual = datetime_date(v)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400,detail='日期格式为(YYYY-MM-DD)')
|
||||
|
||||
today = datetime_date(get_current_date())
|
||||
if actual > today:
|
||||
raise HTTPException(status_code=400,detail='机组日期不能晚于今天')
|
||||
return v
|
||||
@@ -0,0 +1,206 @@
|
||||
"""
|
||||
移民征地相关schema
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional, List
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.validators import DateStr
|
||||
from ..common.datetime import get_current_date
|
||||
|
||||
|
||||
class LarDetailSchema(BaseResponseWithID):
|
||||
id: str = Field(..., description="移民征地id")
|
||||
project_id: Optional[str] = Field(None, description="项目ID")
|
||||
plan_resettlement_pop: Optional[int] = Field(None, description="计划搬迁人数")
|
||||
completed_resettlement_pop: Optional[int] = Field(None, description="完成搬迁人数")
|
||||
|
||||
plan_investment_amt: Optional[float] = Field(None, description="计划投资金额 ")
|
||||
completed_investment_amt: Optional[float] = Field(None, description="完成投资金额 ")
|
||||
|
||||
plan_urban_comp: Optional[float] = Field(None, description="计划城镇补偿金额 ")
|
||||
actual_urban_comp: Optional[float] = Field(None, description="实际城镇补偿金额 ")
|
||||
|
||||
plan_rural_comp: Optional[float] = Field(None, description="计划农村补偿金额 ")
|
||||
actual_rural_comp: Optional[float] = Field(None, description="实际农村补偿金额 ")
|
||||
|
||||
plan_spec_project_reconstr: Optional[float] = Field(None, description="计划专项工程复建 ")
|
||||
actual_spec_project_reconstr: Optional[float] = Field(None, description="实际专项工程复建 ")
|
||||
|
||||
plan_reservoir_bottom_cleanup: Optional[float] = Field(None, description="计划库底清理 ")
|
||||
actual_reservoir_bottom_cleanup: Optional[float] = Field(None, description="实际库底清理 ")
|
||||
|
||||
|
||||
class LarMainInfoUpdateSchema(BaseResponseWithID):
|
||||
id: str = Field(..., description="移民征地id")
|
||||
project_id: str = Field(..., description="项目id")
|
||||
|
||||
plan_urban_comp: float = Field(..., description="计划城镇补偿金额 ")
|
||||
actual_urban_comp: float = Field(..., description="实际城镇补偿金额 ")
|
||||
|
||||
plan_rural_comp: float = Field(..., description="计划农村补偿金额 ")
|
||||
actual_rural_comp: float = Field(..., description="实际农村补偿金额 ")
|
||||
|
||||
plan_spec_project_reconstr: float = Field(..., description="计划专项工程复建 ")
|
||||
actual_spec_project_reconstr: float = Field(..., description="实际专项工程复建 ")
|
||||
|
||||
plan_reservoir_bottom_cleanup: float = Field(..., description="计划库底清理 ")
|
||||
actual_reservoir_bottom_cleanup: float = Field(..., description="实际库底清理 ")
|
||||
|
||||
@field_validator(
|
||||
"plan_urban_comp",
|
||||
"actual_urban_comp",
|
||||
"plan_rural_comp",
|
||||
"actual_rural_comp",
|
||||
"plan_spec_project_reconstr",
|
||||
"actual_spec_project_reconstr",
|
||||
"plan_reservoir_bottom_cleanup",
|
||||
"actual_reservoir_bottom_cleanup",
|
||||
mode="before",
|
||||
)
|
||||
def check_amount_field(cls, v):
|
||||
from fastapi import HTTPException
|
||||
if v is None or v == "":
|
||||
raise HTTPException(detail='金额字段不能为空', status_code=400)
|
||||
if float(v) < 0:
|
||||
raise HTTPException(detail='金额字段需大于等于0', status_code=400)
|
||||
return v
|
||||
|
||||
|
||||
class LarResettlementSchema(BaseResponseWithID):
|
||||
id: str = Field(..., description="移民征地id")
|
||||
project_id: str = Field(..., description="项目id")
|
||||
|
||||
plan_resettlement_pop: int = Field(..., description="计划搬迁人数")
|
||||
completed_resettlement_pop: int = Field(..., description="完成搬迁人数")
|
||||
|
||||
@field_validator(
|
||||
"plan_resettlement_pop",
|
||||
"completed_resettlement_pop",
|
||||
mode="before",
|
||||
)
|
||||
def check_amount_field(cls, v):
|
||||
from fastapi import HTTPException
|
||||
if v is None or v == "":
|
||||
raise HTTPException(detail='搬迁人数不能为空', status_code=400)
|
||||
if float(v) < 0:
|
||||
raise HTTPException(detail='搬迁人数需大于等于0', status_code=400)
|
||||
return v
|
||||
|
||||
|
||||
class LarInvestmentSchema(BaseResponseWithID):
|
||||
id: str = Field(..., description="移民征地id")
|
||||
project_id: str = Field(..., description="项目id")
|
||||
|
||||
plan_investment_amt: float = Field(..., description="计划投资金额")
|
||||
completed_investment_amt: float = Field(..., description="完成投资金额")
|
||||
|
||||
@field_validator(
|
||||
"plan_investment_amt",
|
||||
"completed_investment_amt",
|
||||
mode="before",
|
||||
)
|
||||
def check_amount_field(cls, v):
|
||||
from fastapi import HTTPException
|
||||
if v is None or v == "":
|
||||
raise HTTPException(detail='金额字段不能为空', status_code=400)
|
||||
if float(v) < 0:
|
||||
raise HTTPException(detail='金额字段数需大于等于0', status_code=400)
|
||||
return v
|
||||
|
||||
|
||||
class LarChangeDetailSchema(BaseResponseWithID):
|
||||
project_id: str = Field(..., description="项目ID")
|
||||
title: Optional[str] = Field(None, description="变更事项")
|
||||
reason: Optional[str] = Field(None, description="变更理由")
|
||||
|
||||
before_amount: Optional[float] = Field(None, description="变更前金额")
|
||||
after_amount: Optional[float] = Field(None, description="变更后金额")
|
||||
|
||||
change_time: Optional[str] = Field(None, description="变更时间")
|
||||
attachment_ids: List[str] = Field(default_factory=list, description="附件ID列表", examples=[[]])
|
||||
|
||||
created_at: Optional[str] = Field(None, description="创建时间")
|
||||
created_by_name: Optional[str] = Field(None, description="创建人")
|
||||
|
||||
change_amount: Optional[float] = Field(None, description="变更金额")
|
||||
change_percentage: Optional[str] = Field('', description="变更比例")
|
||||
|
||||
approval_status: Optional[str] = Field(None, description="审批状态")
|
||||
|
||||
attachment_info: List[dict] = Field(
|
||||
default_factory=list, description="文件信息", examples=[[
|
||||
{
|
||||
"id": "54a0daf903a04c8e87cea1175458459d",
|
||||
"name": "54a0daf903a04c8e87cea1175458459d.pdf",
|
||||
"original_name": "新用户注册申请表-项目公司.pdf",
|
||||
"url": "/api/file_download/54a0daf903a04c8e87cea1175458459d"
|
||||
}
|
||||
]]
|
||||
)
|
||||
|
||||
|
||||
class LarChangeInfoSchema(BaseResponseWithID):
|
||||
title: Optional[str] = Field(None, description="变更事项")
|
||||
reason: Optional[str] = Field(None, description="变更理由")
|
||||
|
||||
before_amount: Optional[float] = Field(None, description="变更前金额")
|
||||
after_amount: Optional[float] = Field(None, description="变更后金额")
|
||||
|
||||
change_time: Optional[str] = Field(None, description="变更时间")
|
||||
attachment_ids: List[str] = Field(default_factory=list, description="附件ID列表", examples=[[]])
|
||||
|
||||
approval_status: Optional[str] = Field(None, description="审批状态")
|
||||
|
||||
before_amount_is_edit: Optional[bool] = Field(None, description="变更前金额是否可编辑")
|
||||
|
||||
changed_count: Optional[int] = Field(None, description="已办更次数")
|
||||
|
||||
|
||||
class LarChangeListSchema(BaseModel):
|
||||
page: int
|
||||
page_size: int
|
||||
total: int
|
||||
list: List[LarChangeDetailSchema]
|
||||
|
||||
|
||||
class LarChangeCreateSchema(BaseModel):
|
||||
title: str = Field(..., description="变更事项")
|
||||
reason: str = Field(..., description="变更理由")
|
||||
|
||||
before_amount: float = Field(..., description="变更前金额")
|
||||
after_amount: float = Field(..., description="变更后金额")
|
||||
|
||||
change_time: DateStr = Field(..., description="变更时间")
|
||||
attachment_ids: List[str] = Field(default_factory=list, description="附件ID列表", examples=[[]])
|
||||
|
||||
project_id: str = Field(..., description="项目id")
|
||||
|
||||
@field_validator(
|
||||
"before_amount",
|
||||
"after_amount",
|
||||
mode="before",
|
||||
)
|
||||
def check_amount_field(cls, v):
|
||||
from fastapi import HTTPException
|
||||
if v is None or v == "":
|
||||
raise HTTPException(detail='金额字段不能为空', status_code=400)
|
||||
if float(v) < 0:
|
||||
raise HTTPException(detail='金额字段需大于等于0', status_code=400)
|
||||
return v
|
||||
|
||||
@field_validator(
|
||||
"change_time",
|
||||
mode="before",
|
||||
)
|
||||
def check_actual_time_field(cls, v):
|
||||
from fastapi import HTTPException
|
||||
if v is None or v == "":
|
||||
raise HTTPException(detail='移民变更时间必填', status_code=400)
|
||||
if v > get_current_date():
|
||||
raise HTTPException(detail='移民变更时间不能大于当前日期', status_code=400)
|
||||
return v
|
||||
|
||||
|
||||
class LarChangeUpdateSchema(LarChangeCreateSchema):
|
||||
id: str = Field(..., description="移民变更id")
|
||||
@@ -0,0 +1,39 @@
|
||||
from pydantic import BaseModel, Field,field_validator
|
||||
from typing import Optional
|
||||
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.datetime import datetime_date,get_current_date
|
||||
from fastapi import HTTPException
|
||||
from ..common.validators import DateStr
|
||||
|
||||
class PostPreparation(BaseModel):
|
||||
id:str = Field(..., description="里程碑ID")
|
||||
code: str= Field(..., description="里程碑的节点编码")
|
||||
acquire_date: DateStr|None = Field(None,description="取得时间")
|
||||
is_exist: bool= Field(..., description="是否取得")
|
||||
|
||||
@field_validator('acquire_date')
|
||||
def validate_acquire_date(cls, v: Optional[DateStr]) -> Optional[DateStr]:
|
||||
if v is None:
|
||||
return None
|
||||
try:
|
||||
actual = datetime_date(v)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400,detail='日期格式为(YYYY-MM-DD)')
|
||||
|
||||
today = datetime_date(get_current_date())
|
||||
if actual > today:
|
||||
raise HTTPException(status_code=400,detail='取得时间不能晚于今天')
|
||||
return v
|
||||
|
||||
|
||||
class PreparationDetail(BaseResponseWithID):
|
||||
id: Optional[str] = Field(None, description="里程碑ID")
|
||||
project_id: Optional[str] = Field(None, description="项目ID")
|
||||
code: Optional[str] = Field(None, description="里程碑节点编码")
|
||||
acquire_date: Optional[DateStr] = Field(None, description="取得时间")
|
||||
is_exist: Optional[bool] = Field(None, description="是否取得")
|
||||
approval_status: Optional[str] = Field(None, description="审批状态")
|
||||
name: Optional[str] = Field(None, description="里程碑名称")
|
||||
group: Optional[str] = Field(None, description="分组条件", examples=['KGTJLS'])
|
||||
is_acquired: Optional[int] = Field(0, description="是否取得")
|
||||
@@ -0,0 +1,39 @@
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional
|
||||
|
||||
from ..common.base import BaseResponseWithID
|
||||
from ..common.datetime import datetime_date, get_current_date
|
||||
from fastapi import HTTPException
|
||||
from ..common.validators import DateStr
|
||||
|
||||
|
||||
class PostProduction(BaseModel):
|
||||
id: str = Field(..., description="投产节点ID")
|
||||
code: str = Field(..., description="节点编码")
|
||||
acquire_date: DateStr | None = Field(None, description="取得时间")
|
||||
is_exist: bool = Field(..., description="是否取得")
|
||||
|
||||
@field_validator('acquire_date')
|
||||
def validate_acquire_date(cls, v: Optional[DateStr]) -> Optional[DateStr]:
|
||||
if v is None:
|
||||
return None
|
||||
try:
|
||||
actual = datetime_date(v)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail='日期格式为(YYYY-MM-DD)')
|
||||
|
||||
today = datetime_date(get_current_date())
|
||||
if actual > today:
|
||||
raise HTTPException(status_code=400, detail='取得时间不能晚于今天')
|
||||
return v
|
||||
|
||||
|
||||
class ProductionDetail(BaseResponseWithID):
|
||||
id: Optional[str] = Field(None, description="投产节点ID")
|
||||
project_id: Optional[str] = Field(None, description="项目ID")
|
||||
code: Optional[str] = Field(None, description="投产节点编码")
|
||||
acquire_date: Optional[DateStr] = Field(None, description="取得时间")
|
||||
is_exist: Optional[bool] = Field(None, description="是否取得")
|
||||
approval_status: Optional[str] = Field(None, description="审批状态")
|
||||
name: Optional[str] = Field(None, description="投产节点名称")
|
||||
is_acquired: Optional[int] = Field(0, description="是否取得")
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
项目容量信息schema
|
||||
只提供返回,不提供更新接口
|
||||
"""
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, List
|
||||
from ..common.base import BaseResponseWithID
|
||||
|
||||
|
||||
class ProjectDetailKey(str, Enum):
|
||||
"""项目子类类型枚举"""
|
||||
PLAN_CONSTRUCTION = "plan_construction" # 计划在建容量
|
||||
ACTUAL_CONSTRUCTION = "actual_construction" # 实际在建容量
|
||||
PRODUCTION = "production" # 投产容量
|
||||
ENSURE_PRODUCTION = "ensure_production" # 确保容量
|
||||
CLIMB_PRODUCTION = "climb_production" # 登高容量
|
||||
CHALLENGE_PRODUCTION = "challenge_production" # 揭榜容量
|
||||
COMPLETE_INVESTMENT = "complete_investment" # 完成投资容量
|
||||
|
||||
|
||||
class CapacityItem(BaseModel):
|
||||
year: Optional[int] = Field(None, description='年')
|
||||
date: Optional[str] = Field(None, description="日期,格式YYYY-MM-DD")
|
||||
capacity: float = Field(..., description='容量')
|
||||
is_audit: Optional[bool] = Field(False, description='是否可编辑')
|
||||
|
||||
|
||||
class ProjectDetailProject(BaseResponseWithID):
|
||||
project_id:str= Field(..., description="所属项目ID", examples=["project123"])
|
||||
key: Optional[ProjectDetailKey] = Field(None, description='项目子类类型')
|
||||
value: Optional[List[CapacityItem]] = Field(None, description='项目子类类型值')
|
||||
@@ -0,0 +1,7 @@
|
||||
from .photovotaic import PhotovoltaicExtension
|
||||
from .onshore_wind import OnShoreWindExtension
|
||||
from .offshore_wind import OffShoreWindExtension
|
||||
from .hydropower import HydropowerExtension
|
||||
from .pumped_storage import PumpedStorageExtension
|
||||
from .gas_turbine import GasTurbineExtension
|
||||
from .thermal_power import ThermalPowerExtension
|
||||
@@ -0,0 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List, Optional, Literal
|
||||
from ..common.validators import DateStr
|
||||
|
||||
class GasTurbineExtension(BaseModel):
|
||||
"""
|
||||
燃气轮机项目特定字段
|
||||
"""
|
||||
pass
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user