v0.2.0: CRM/ERP 系统升级 - 清理 .gitignore 并移除误提交的 venv/env/db 文件

- 更新 .gitignore:全面覆盖环境变量、数据库、日志、缓存、上传文件
- 移除误跟踪的 server/venv/、crm_data.db、.env 文件
- 新增 server/.env.example 模板
- 新增合同管理、利润核算、AI教练等功能模块
- 新增 Playwright e2e 测试套件
- 前后端多项功能升级和 bug 修复
This commit is contained in:
hankin
2026-05-11 07:24:19 +00:00
parent 0f4c6b7924
commit 815cbf9d8c
2526 changed files with 11875 additions and 804148 deletions
+26 -1
View File
@@ -7,7 +7,7 @@ import uuid
from datetime import date, datetime
from sqlalchemy import Boolean, Date, DateTime, ForeignKey, SmallInteger, String, Text, func
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.dialects.postgresql import UUID, JSONB, ARRAY
from sqlalchemy.orm import Mapped, mapped_column
from app.models.base import Base
@@ -30,11 +30,19 @@ class SalesLog(Base):
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
salesperson_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("sys_users.id"), nullable=False)
involved_company_ids: Mapped[list] = mapped_column(
ARRAY(UUID(as_uuid=True)), nullable=False, default=list,
comment="该篇日志涉及的公司ID列表"
)
customer_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("crm_customers.id"), nullable=True)
content: Mapped[str] = mapped_column(Text, nullable=False)
log_date: Mapped[date] = mapped_column(Date, default=date.today)
contact_ids: Mapped[list | None] = mapped_column(JSONB, default=list, nullable=True)
ai_processed: Mapped[bool] = mapped_column(Boolean, default=False)
ai_coaching_feedback: Mapped[dict | None] = mapped_column(
JSONB, default=dict, nullable=True,
comment="AI 教练引擎回写的指导反馈"
)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
is_deleted: Mapped[bool] = mapped_column(Boolean, default=False)
@@ -53,3 +61,20 @@ class AiReportDraft(Base):
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
is_deleted: Mapped[bool] = mapped_column(Boolean, default=False)
class KbObsidianVector(Base):
"""知识库向量表 —— pgvector 存储 Obsidian 文档分块向量"""
__tablename__ = "kb_obsidian_vectors"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
company_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("sys_companies.id"), nullable=False, index=True
)
source_path: Mapped[str] = mapped_column(String(500), nullable=False, comment="源文件路径")
chunk_index: Mapped[int] = mapped_column(SmallInteger, default=0)
content: Mapped[str] = mapped_column(Text, nullable=False)
metadata_: Mapped[dict | None] = mapped_column("metadata", JSONB, default=dict)
# 向量字段使用 raw SQL 创建(vector(1536))因 SQLAlchemy 无原生 pgvector 类型
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
is_deleted: Mapped[bool] = mapped_column(Boolean, default=False)