133 lines
5.1 KiB
Python
133 lines
5.1 KiB
Python
from __future__ import annotations
|
|
|
|
from app.core.agent_enums import AgentReviewStatus
|
|
from app.schemas.agent_asset import (
|
|
AgentAssetSpreadsheetChangeRecordRead,
|
|
AgentAssetSpreadsheetDiffCellRead,
|
|
AgentAssetSpreadsheetDiffSheetRead,
|
|
AgentAssetVersionTimelineItemRead,
|
|
)
|
|
|
|
|
|
class AgentAssetTimelineMixin:
|
|
def list_version_timeline(self, asset_id: str) -> list[AgentAssetVersionTimelineItemRead]:
|
|
self._ensure_ready()
|
|
asset = self.repository.get(asset_id)
|
|
if asset is None:
|
|
raise LookupError("Asset not found")
|
|
|
|
events: list[AgentAssetVersionTimelineItemRead] = []
|
|
versions = self.repository.list_versions(asset_id)
|
|
for version in versions:
|
|
source_version = self._extract_restore_source_version(version.change_note)
|
|
events.append(
|
|
AgentAssetVersionTimelineItemRead(
|
|
event_type="restored" if source_version else "created",
|
|
version=version.version,
|
|
actor=version.created_by,
|
|
event_time=version.created_at,
|
|
title="恢复生成工作稿" if source_version else "创建工作版本",
|
|
description=version.change_note or "生成新版本",
|
|
note=version.change_note,
|
|
source_version=source_version,
|
|
)
|
|
)
|
|
|
|
for review in self.repository.list_reviews(asset_id):
|
|
event_type = {
|
|
AgentReviewStatus.PENDING.value: "submitted",
|
|
AgentReviewStatus.APPROVED.value: "approved",
|
|
AgentReviewStatus.REJECTED.value: "rejected",
|
|
}.get(review.review_status, "reviewed")
|
|
title = {
|
|
"submitted": "提交审核",
|
|
"approved": "审核通过",
|
|
"rejected": "审核驳回",
|
|
}.get(event_type, "审核处理")
|
|
events.append(
|
|
AgentAssetVersionTimelineItemRead(
|
|
event_type=event_type,
|
|
version=review.version,
|
|
actor=review.reviewer,
|
|
event_time=review.reviewed_at or review.created_at,
|
|
title=title,
|
|
description=review.review_note or "",
|
|
note=review.review_note,
|
|
)
|
|
)
|
|
|
|
audit_logs = self.audit_service.repository.list(
|
|
resource_type=asset.asset_type,
|
|
resource_id=asset.id,
|
|
limit=200,
|
|
)
|
|
for log in audit_logs:
|
|
if log.action != "activate_agent_asset":
|
|
continue
|
|
after_json = log.after_json or {}
|
|
version = str(
|
|
after_json.get("published_version")
|
|
or after_json.get("current_version")
|
|
or ""
|
|
).strip()
|
|
if not version:
|
|
continue
|
|
events.append(
|
|
AgentAssetVersionTimelineItemRead(
|
|
event_type="published",
|
|
version=version,
|
|
actor=log.actor,
|
|
event_time=log.created_at,
|
|
title="正式上线",
|
|
description="该版本已切换为线上正式版本。",
|
|
)
|
|
)
|
|
|
|
return sorted(events, key=lambda item: item.event_time)
|
|
|
|
def list_spreadsheet_change_records(
|
|
self,
|
|
asset_id: str,
|
|
*,
|
|
limit: int = 30,
|
|
) -> list[AgentAssetSpreadsheetChangeRecordRead]:
|
|
self._ensure_ready()
|
|
asset = self._require_spreadsheet_rule(asset_id)
|
|
logs = self.audit_service.repository.list(
|
|
resource_type=asset.asset_type,
|
|
resource_id=asset.id,
|
|
action="edit_rule_spreadsheet",
|
|
limit=min(max(limit, 1), 30),
|
|
)
|
|
return [
|
|
AgentAssetSpreadsheetChangeRecordRead(
|
|
id=log.id,
|
|
actor=log.actor,
|
|
changed_at=log.created_at,
|
|
summary=str((log.after_json or {}).get("summary") or "表格内容已保存。"),
|
|
sheet_changes=[
|
|
AgentAssetSpreadsheetDiffSheetRead.model_validate(item)
|
|
for item in ((log.after_json or {}).get("sheet_changes") or [])
|
|
],
|
|
cell_changes=[
|
|
AgentAssetSpreadsheetDiffCellRead.model_validate(item)
|
|
for item in ((log.after_json or {}).get("cell_changes") or [])
|
|
],
|
|
changed_sheet_count=int((log.after_json or {}).get("changed_sheet_count") or 0),
|
|
changed_cell_count=int((log.after_json or {}).get("changed_cell_count") or 0),
|
|
)
|
|
for log in logs
|
|
]
|
|
|
|
|
|
@staticmethod
|
|
def _extract_restore_source_version(change_note: str | None) -> str | None:
|
|
normalized = str(change_note or "").strip()
|
|
prefix = "基于历史版本 "
|
|
suffix = " 恢复生成工作稿"
|
|
if not normalized.startswith(prefix) or suffix not in normalized:
|
|
return None
|
|
return normalized.removeprefix(prefix).split(suffix, 1)[0].strip() or None
|
|
|
|
|