platform-assistant/apps/api/prisma/schema.prisma
Sisyphus 4ab0040e55 feat(F002-P1): Lead 加 notes 字段 + crawler 提取 PDF 6 条要点 (老 GUI 同款)
- Lead 模型加 3 字段: notes (5000 字) / notesExtractedAt / notesSource
- 新增 NotesExtractorService (crawler 模块): PDF/HTML/URL → text → DeepSeek → 6 条要点
- 新增 LeadNotesController: POST /api/lead-notes/extract/:leadId (24h 缓存 + forceRefresh)
- lead.service.ts publishToDirev 优先用 notes 填 publishArgs.description + 同步传 notes
- Java publish() 已有逻辑: notes 优先 → description, 不需要改
- 端到端验证: Lead.notes=6 条要点 → publishToDirev → B2B tb_inquiry.note 正确落地

依赖: pdf-parse (新加, 1 个 npm 包, 25KB)

API 端点:
- POST /api/lead-notes/extract/:leadId?sourcePath=<URL|路径>&forceRefresh=false
- 返 { notes: string, source: 'pdf'|'html'|'url', cached: boolean }

环境变量: DEEPSEEK_API_KEY (从 .env 读, 缺时报错)

关联: F002-W31-交接文档.md §4 P1
本地备份: ~/projects/_meta/f002-fix/w31-platform-assistant-2026-06-23/
2026-06-24 11:52:59 +08:00

233 lines
6.5 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model Lead {
id String @id @default(uuid())
title String
noticeId String?
detailUrl String?
level String @default("C")
status String @default("待复核")
star Int @default(0)
amount String @default("待确认")
category String?
organization String?
region String?
regionDetail String? // 详细收货地址(区别于 region 省份/区域)
source String?
contact String?
phone String?
email String?
deadline String?
quantity Int? // 询价数量
unit String? // 单位(件/吨/米/台等)
attachments String? // JSON 数组字符串(附件 URL 列表)
notes String? // W31 P1: 公告 6 条商务要点摘要 (PDF → DeepSeek → 商家报价时看)
notesExtractedAt DateTime? // notes 提取时间, 用于判断是否过期
notesSource String? // notes 来源 ("pdf" / "html" / "url"), 留痕
summary String?
reason String?
analysisLogic String?
aiScore Float?
scoringDetails String?
publish String @default("未发布")
publishTime String? // 原始公告的发布时间(从抓取源读取)
publishedAt DateTime?
inquiryNo String?
direvUrl String?
assignedTo String?
followLogs String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([source, noticeId])
}
model Rule {
id String @id @default(uuid())
name String
type String
config String
enabled Boolean @default(true)
userId String @default("default")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model RuleVersion {
id String @id @default(uuid())
ruleId String
version Int
config String
userId String?
createdAt DateTime @default(now())
}
model Report {
id String @id @default(uuid())
title String
type String
status String @default("generating")
config String?
channels String?
fileUrl String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model AuditLog {
id String @id @default(uuid())
action String
detail String
operator String
ip String?
userId String @default("default")
createdAt DateTime @default(now())
}
model CrawlerConfig {
id String @id @default(uuid())
name String
targetUrl String
status String @default("active")
type String @default("bid")
sourceName String?
scriptPath String?
schedule String?
keywords String?
categories String?
lastRunAt DateTime?
totalRuns Int @default(0)
successRuns Int @default(0)
failedRuns Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Inquiry {
id String @id @default(uuid())
title String
source String
url String
budget String?
deadline String?
buyer String
category String
status String @default("pending")
level String @default("C")
star Int @default(0)
region String?
contact String?
phone String?
aiScore Float?
assignedTo String?
inquiryNo String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Product {
id String @id @default(uuid())
name String
spec String
unit String
price Float
quantity Int
imageUrl String?
category String
status String @default("draft")
brand String?
supplier String?
minOrder Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Tenant {
id String @id @default(uuid())
companyName String
contactName String?
contactEmail String?
plan String @default("basic")
status String @default("active")
validFrom DateTime @default(now())
validUntil DateTime
platformType String?
platformUrl String?
platformApiKey String?
features String?
usageQuotas String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
users User[]
}
model User {
id String @id @default(uuid())
email String? @unique
username String? @unique
password String
name String?
phone String?
role String @default("user")
isActive Boolean @default(true)
tenantId String?
tenant Tenant? @relation(fields: [tenantId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model GeneratedImage {
id String @id @default(uuid())
productName String
url String
status String @default("generating")
style String?
sourceHash String?
createdAt DateTime @default(now())
}
model ImageLibrary {
id String @id @default(uuid())
productName String
keyword String?
filePath String
source String @default("baidu")
style String?
ratio String?
createdAt DateTime @default(now())
}
model SystemConfig {
id String @id @default(uuid())
key String @unique
value String
group String @default("general")
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Integration {
id String @id @default(uuid())
name String // 对接名称,如 "B2B 询价平台"
type String @default("mcp") // "mcp" | "http" | "custom"
endpoint String // MCP server 地址 (devbox 开发机), 如 "http://100.111.84.16:3002/mcp"
appId String? // B2B 运营后台"集成管理"申请到的 appId (公开 ID, 非敏感)
apiKey String? // appSecret (加密存储) - 对应 B2B 运营后台 app_secret
customerCode String? // 客户编码 (冗余, 实际由 MCP 验证后从 X-Customer-Code 头获取)
status String @default("inactive") // "active" | "inactive" | "error"
tools String? // JSON: 可用工具列表
lastConnected DateTime? // 最后成功连接时间
error String? // 最近错误信息
companyUserId String? // W31: 公司账号 ID (从 B2B 后端 open_api_app 表来, 用于一键发布时自动填 enterpriseId/userId; 用 String 存避免 JS Number 精度丢失)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}