feat: 添加生命周期报告和AI规则管理功能

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

View File

@@ -0,0 +1,118 @@
"""Add project contracts and normalized cash flows.
Revision ID: 202607120002
Revises: 202607120001
Create Date: 2026-07-12
"""
from alembic import op
import sqlalchemy as sa
revision = "202607120002"
down_revision = "202607120001"
branch_labels = None
depends_on = None
def _index(table: str, column: str, unique: bool = False) -> None:
op.create_index(op.f(f"ix_{table}_{column}"), table, [column], unique=unique)
def upgrade() -> None:
op.add_column(
"projects", sa.Column("source_contract_amount", sa.Numeric(16, 2), nullable=True)
)
op.add_column(
"projects",
sa.Column("source_project_investment_amount", sa.Numeric(16, 2), nullable=True),
)
op.create_table(
"project_contracts",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("code", sa.String(64), nullable=False),
sa.Column("project_code", sa.String(64), nullable=True),
sa.Column("contract_type_code", sa.String(32), nullable=True),
sa.Column("contract_type_label", sa.String(128), nullable=True),
sa.Column("amount", sa.Numeric(16, 2), nullable=False),
sa.Column("signed_date", sa.Date(), nullable=True),
sa.Column("start_date", sa.Date(), nullable=True),
sa.Column("end_date", sa.Date(), nullable=True),
sa.Column("invoice_type_code", sa.String(32), nullable=True),
sa.Column("data_quality_status", sa.String(32), nullable=False),
sa.Column("source_system", sa.String(64), nullable=False),
sa.Column("external_id", sa.String(128), nullable=False),
sa.Column("source_created_at", sa.DateTime(), nullable=True),
sa.Column("last_seen_at", sa.DateTime(), nullable=True),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
for column, unique in (
("code", True),
("project_code", False),
("contract_type_code", False),
("signed_date", False),
("data_quality_status", False),
("external_id", False),
("last_seen_at", False),
("is_active", False),
):
_index("project_contracts", column, unique)
op.create_table(
"project_cash_flows",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("code", sa.String(64), nullable=False),
sa.Column("project_code", sa.String(64), nullable=True),
sa.Column("contract_code", sa.String(64), nullable=True),
sa.Column("flow_type", sa.String(32), nullable=False),
sa.Column("direction", sa.String(16), nullable=False),
sa.Column("category_code", sa.String(32), nullable=True),
sa.Column("category_label", sa.String(128), nullable=True),
sa.Column("planned_amount", sa.Numeric(16, 2), nullable=False),
sa.Column("actual_amount", sa.Numeric(16, 2), nullable=True),
sa.Column("planned_date", sa.Date(), nullable=True),
sa.Column("actual_date", sa.Date(), nullable=True),
sa.Column("payment_status", sa.String(32), nullable=True),
sa.Column("invoice_status", sa.String(32), nullable=True),
sa.Column("approval_status", sa.String(32), nullable=True),
sa.Column("confirmation_status", sa.String(32), nullable=True),
sa.Column("data_quality_status", sa.String(32), nullable=False),
sa.Column("source_system", sa.String(64), nullable=False),
sa.Column("external_id", sa.String(128), nullable=False),
sa.Column("source_created_at", sa.DateTime(), nullable=True),
sa.Column("source_updated_at", sa.DateTime(), nullable=True),
sa.Column("last_seen_at", sa.DateTime(), nullable=True),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
for column, unique in (
("code", True),
("project_code", False),
("contract_code", False),
("flow_type", False),
("direction", False),
("category_code", False),
("planned_date", False),
("actual_date", False),
("payment_status", False),
("approval_status", False),
("data_quality_status", False),
("external_id", False),
("source_updated_at", False),
("last_seen_at", False),
("is_active", False),
):
_index("project_cash_flows", column, unique)
def downgrade() -> None:
op.drop_table("project_cash_flows")
op.drop_table("project_contracts")
op.drop_column("projects", "source_project_investment_amount")
op.drop_column("projects", "source_contract_amount")