Files
company-ai-platform/app/modules/reports/services/lifecycle/report.py
JiuContinent 9cf7c44393 ```
feat: 添加生命周期报告和AI规则管理功能

- 在Dockerfile中添加pillow依赖包用于图像处理
- 实现生命周期报告调度任务,支持日报和周报两种类型
- 新增TASK_RUN_LIFECYCLE任务常量和相关配置选项
- 扩展AI Agent服务以支持用户规则,并在分析时应用规则
- 添加AI用户规则创建、更新和查询接口
- 增加项目生命周期和财务需求分析技能
- 扩展现有模型以支持更完整的业务数据字段
- 实现飞书图片上传功能用于报告展示
```
2026-07-12 17:44:49 +08:00

113 lines
4.4 KiB
Python

from datetime import date
from typing import Any
from app.core.constants import ActorValue
from app.core.config import get_settings
from app.modules.reports.constants import (
LifecycleFilterKey,
LifecycleResponseKey,
LifecycleSection,
ReportTitle,
)
from app.modules.reports.services.common import _json_safe
class ReportLifecycleReportMixin:
def project_lifecycle_report(
self,
project_code: str | None = None,
owner: str | None = None,
period_start: date | None = None,
period_end: date | None = None,
include_ai: bool = False,
actor: str = ActorValue.API,
) -> dict[str, Any]:
"""Build a full lifecycle report for project progress, delivery, cost, and risk."""
filters = self._lifecycle_filters(project_code, owner, period_start, period_end)
project_conditions = filters[LifecycleSection.PROJECTS]
task_conditions = filters[LifecycleSection.TASKS]
procurement_conditions = filters[LifecycleSection.PROCUREMENTS]
expense_conditions = filters[LifecycleSection.EXPENSES]
attendance_conditions = filters[LifecycleSection.ATTENDANCE]
risk_conditions = filters[LifecycleSection.RISKS]
project_stats = self._lifecycle_project_stats(project_conditions)
task_stats = self._lifecycle_task_stats(task_conditions)
procurement_stats = self._lifecycle_procurement_stats(procurement_conditions)
expense_stats = self._lifecycle_expense_stats(expense_conditions)
fund_stats = self._lifecycle_fund_stats()
supplier_stats = self._lifecycle_supplier_stats()
attendance_stats = self._lifecycle_attendance_stats(attendance_conditions)
risk_stats = self._lifecycle_risk_stats(
project_conditions,
task_conditions,
risk_conditions,
)
include_global_risk = not (project_code or owner)
health = self._lifecycle_health(
project_stats,
task_stats,
risk_stats,
supplier_stats,
include_global_risk,
)
attention = self._lifecycle_attention(project_conditions, task_conditions)
recommendations = self._lifecycle_recommendations(
project_stats,
task_stats,
procurement_stats,
expense_stats,
fund_stats,
supplier_stats,
risk_stats,
include_global_risk,
)
finance = (
self.project_finance_needs_report(
project_code=project_code,
owner=owner,
as_of=period_end,
include_ai=False,
actor=actor,
)
if get_settings().finance_needs_enabled
else None
)
metrics = {
LifecycleSection.HEALTH: health,
LifecycleSection.PROJECTS: project_stats,
LifecycleSection.TASKS: task_stats,
LifecycleSection.PROCUREMENTS: procurement_stats,
LifecycleSection.EXPENSES: expense_stats,
LifecycleSection.FUNDS: fund_stats,
LifecycleSection.SUPPLIERS: supplier_stats,
LifecycleSection.ATTENDANCE: attendance_stats,
LifecycleSection.RISKS: risk_stats,
LifecycleSection.FINANCE: finance["summary"] if finance else {"status": "未启用"},
}
lines = self._lifecycle_lines(
filters[LifecycleFilterKey.LABELS],
metrics,
recommendations,
)
if finance:
lines.extend(finance[LifecycleResponseKey.LINES])
report = {
LifecycleResponseKey.TITLE: ReportTitle.PROJECT_LIFECYCLE,
LifecycleResponseKey.FILTERS: filters[LifecycleFilterKey.LABELS],
LifecycleResponseKey.METRICS: _json_safe(metrics),
LifecycleResponseKey.ATTENTION: _json_safe(attention),
LifecycleResponseKey.RECOMMENDATIONS: recommendations,
LifecycleResponseKey.LINES: lines,
LifecycleResponseKey.CONTENT: "\n".join(lines),
"source_lifecycle": self.source_project_lifecycle_summary(project_code, owner),
"finance": finance,
"finance_chart_data": finance["finance_chart_data"] if finance else None,
}
if include_ai:
report[LifecycleResponseKey.AI_ANALYSIS] = self._lifecycle_ai_analysis(report, actor)
return report