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
+79 -3
View File
@@ -3,11 +3,13 @@
"""
from __future__ import annotations
import uuid
import asyncio
from fastapi import APIRouter, Depends, Body
from fastapi import APIRouter, Depends, Body, HTTPException
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_current_user
from app.api.deps import get_current_user, get_current_company_id
from app.db.database import get_db
from app.schemas.auth import CurrentUserPayload
from app.schemas.response import ok
@@ -26,6 +28,7 @@ async def list_logs(
end_date: str | None = None,
db: AsyncSession = Depends(get_db),
current_user: CurrentUserPayload = Depends(get_current_user),
company_id: uuid.UUID = Depends(get_current_company_id),
):
result = await sales_log_service.list_logs(
db, current_user,
@@ -34,18 +37,56 @@ async def list_logs(
user_id=user_id,
start_date=start_date,
end_date=end_date,
company_id=company_id,
)
return ok(data=result)
async def _resolve_company_ids(
db: AsyncSession,
company_id: uuid.UUID,
customer_id: str | None,
company_ids: list[str] | None,
) -> list[uuid.UUID]:
"""
智能解析 involved_company_ids
1. 如果前端显式传了 company_ids,使用它
2. 否则以当前视角公司为基础
3. 如果选了客户,自动查客户 owner 所属的公司,合并进来
"""
if company_ids:
resolved = set(uuid.UUID(cid) for cid in company_ids)
else:
resolved = {company_id}
# 自动关联客户 owner 所在公司
if customer_id:
from app.models.crm import CrmCustomer
from app.models.sys import SysUserCompany
cust = await db.get(CrmCustomer, uuid.UUID(customer_id))
if cust and cust.owner_id:
stmt = select(SysUserCompany.company_id).where(
SysUserCompany.user_id == cust.owner_id
)
rows = (await db.execute(stmt)).scalars().all()
for cid in rows:
resolved.add(cid)
# 确保当前公司始终在内
resolved.add(company_id)
return list(resolved)
@router.post("", summary="创建销售日志")
async def create_log(
content: str = Body(..., embed=True),
customer_id: str | None = Body(None, embed=True),
contact_ids: list[str] | None = Body(None, embed=True),
log_date: str | None = Body(None, embed=True),
company_ids: list[str] | None = Body(None, embed=True),
db: AsyncSession = Depends(get_db),
current_user: CurrentUserPayload = Depends(get_current_user),
company_id: uuid.UUID = Depends(get_current_company_id),
):
from datetime import date as date_type
@@ -53,17 +94,20 @@ async def create_log(
if log_date:
parsed_date = date_type.fromisoformat(log_date)
# 智能解析公司关联
resolved_company_ids = await _resolve_company_ids(db, company_id, customer_id, company_ids)
result = await sales_log_service.create_log(
db, current_user,
content=content,
customer_id=customer_id,
contact_ids=contact_ids,
log_date=parsed_date,
company_ids=resolved_company_ids,
)
# 异步触发 Dify 画像提取工作流(仅当关联了客户时)
if customer_id:
import uuid
asyncio.create_task(
sales_log_service.trigger_persona_workflow(
log_id=uuid.UUID(result["id"]),
@@ -75,3 +119,35 @@ async def create_log(
)
return ok(data=result, message="日志创建成功")
@router.put("/{log_id}", summary="编辑销售日志")
async def update_log(
log_id: uuid.UUID,
content: str | None = Body(None, embed=True),
customer_id: str | None = Body(None, embed=True),
contact_ids: list[str] | None = Body(None, embed=True),
log_date: str | None = Body(None, embed=True),
db: AsyncSession = Depends(get_db),
current_user: CurrentUserPayload = Depends(get_current_user),
company_id: uuid.UUID = Depends(get_current_company_id),
):
result = await sales_log_service.update_log(
db, current_user, log_id,
content=content,
customer_id=customer_id,
contact_ids=contact_ids,
log_date=log_date,
company_id=company_id,
)
return ok(data=result, message="日志更新成功")
@router.delete("/{log_id}", summary="删除销售日志(软删除)")
async def delete_log(
log_id: uuid.UUID,
db: AsyncSession = Depends(get_db),
current_user: CurrentUserPayload = Depends(get_current_user),
):
await sales_log_service.delete_log(db, current_user, log_id)
return ok(message="日志已删除")