platform-assistant/apps/api/prisma/schema.prisma
Sisyphus 58ac140802 feat: 品类方案C - AI分类 + 关键词表反哺
- 新增 ProductCategory 表(schema + migration + seed 15个品类)
- 新增 product-category CRUD API(GET/POST/PUT/DELETE /api/categories)
- 新增 CategoryInferenceService:关键词匹配优先,失败时调 DeepSeek AI 分类,结果反写品类表
- 更新 CrawlerService:采集入库时使用 batchInfer 替代硬编码 inferCategory
- 更新 LeadService:品类筛选改为 DB 关键词匹配,移除硬编码 CATEGORY_KEYWORDS
- 修复 LeadModule/CrawlerModule 依赖关系,避免循环依赖
2026-06-30 18:37:23 +08:00

242 lines
6.9 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
}
model ProductCategory {
id String @id @default(uuid())
name String @unique // 品类名, 如 "电线电缆"
keywords String // JSON 数组: ["电缆","电线","导线"]
isAIGenerated Boolean @default(false) // 是否由 AI 自动分类生成
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}