优化sync_system代码质量

This commit is contained in:
strepsiades
2026-04-01 11:52:57 +08:00
parent eb02fd32a5
commit 8f4727a772
46 changed files with 1431 additions and 890 deletions
@@ -107,6 +107,8 @@ class ProjectApiHandler(BaseApiHandler):
project_id: 可选,指定项目ID列表则只加载这些项目(优先级高于构造函数的filter_project_id
"""
try:
self.ensure_api_client()
self.ensure_collection()
# 清空旧缓存
self.clear_cache()
@@ -21,6 +21,8 @@ class ProjectSyncSchema(ProjectResponseBase):
completed_investment: float | None = Field(None, description="已完成投资")
total_contract_quantity: float | None = Field(None, description="合同总量")
completed_settlement_quantity: float | None = Field(None, description="已结算量")
ic_plan_first_production_date: str | None = Field(None, description="集团计划首批投产日期")
ic_plan_full_production_date: str | None = Field(None, description="集团计划全容量投产日期")
class ProjectSyncNode(SyncNode[ProjectSyncSchema]):
@@ -1,8 +1,14 @@
from pydantic import BaseModel
from ...sync_system.strategy import DefaultSyncStrategy
from ...sync_system.config import StrategyConfig, OrphanAction, UpdateDirection
from schemas.project.project_base import ProjectResponseBase
class ProjectDomainOption(BaseModel):
pull_group_plan_production_date: bool = False
class ProjectSyncStrategy(DefaultSyncStrategy[ProjectResponseBase]):
"""
Project 同步策略
@@ -17,6 +23,12 @@ class ProjectSyncStrategy(DefaultSyncStrategy[ProjectResponseBase]):
# 类变量:schema 固定为 ProjectResponseBase
schema = ProjectResponseBase
domain_option_model = ProjectDomainOption
_PULL_ONLY_FIELDS = [
"ic_plan_first_production_date",
"ic_plan_full_production_date",
]
# 类变量:默认配置
default_config = StrategyConfig(
@@ -26,4 +38,60 @@ class ProjectSyncStrategy(DefaultSyncStrategy[ProjectResponseBase]):
local_orphan_action=OrphanAction.CREATE_REMOTE,
remote_orphan_action=OrphanAction.NONE,
update_direction=UpdateDirection.PUSH,
)
)
@property
def domain_option(self) -> ProjectDomainOption:
return ProjectDomainOption.model_validate(self.config.domain_option)
def get_node_update_payload(self, node):
payload = dict(node.get_data() or {})
context = getattr(node, "context", None)
if not isinstance(context, dict):
return payload
all_info = context.get("all_info")
if not isinstance(all_info, dict):
return payload
for section_name, section_data in all_info.items():
if not section_name.endswith("_extension") or not isinstance(section_data, dict):
continue
for field_name in self._PULL_ONLY_FIELDS:
if payload.get(field_name) not in (None, ""):
continue
if field_name in section_data:
payload[field_name] = section_data.get(field_name)
return payload
async def update_pair(self, local_node, remote_node, data_id_map=None):
updated_by_id = {}
if self.domain_option.pull_group_plan_production_date:
pull_update = await self.prepare_update_for_direction(
local_node,
remote_node,
UpdateDirection.PULL,
data_id_map,
include_fields=self._PULL_ONLY_FIELDS,
)
if pull_update is not None:
updated_by_id[pull_update.node_id] = pull_update
generic_exclude_fields = self._PULL_ONLY_FIELDS
else:
generic_exclude_fields = None
if self.config.update_direction != UpdateDirection.NONE:
generic_update = await self.prepare_update_for_direction(
local_node,
remote_node,
self.config.update_direction,
data_id_map,
exclude_fields=generic_exclude_fields,
)
if generic_update is not None:
updated_by_id[generic_update.node_id] = generic_update
return list(updated_by_id.values())