docs: 完善技术文档
新增文档: - api/API接口文档模板.md - api/PLM-API接口文档-V2.md - api/产品服务API文档-V2.md - architecture/BOM服务技术文档.md - architecture/PLM技术文档摘要.md - development/M1-S4开发手册.md - development/PLM开发手册.md - development/PLM开发文档.md - operations/系统部署指南.md - operations/部署检查清单.md 提交人: creator 提交时间: 2026-04-03
This commit is contained in:
290
api/API接口文档模板.md
Normal file
290
api/API接口文档模板.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# API 接口文档模板
|
||||
|
||||
> **版本**:V1.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子
|
||||
> **状态**:模板
|
||||
|
||||
---
|
||||
|
||||
## 一、API 设计规范
|
||||
|
||||
### 1.1 RESTful API 规范
|
||||
|
||||
```
|
||||
基础URL: https://api.plm.example.com/v1
|
||||
|
||||
HTTP方法:
|
||||
- GET 查询资源
|
||||
- POST 创建资源
|
||||
- PUT 更新资源(全量)
|
||||
- PATCH 更新资源(部分)
|
||||
- DELETE 删除资源
|
||||
```
|
||||
|
||||
### 1.2 响应格式
|
||||
|
||||
**成功响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
// 业务数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 40001,
|
||||
"message": "参数错误",
|
||||
"errors": [
|
||||
{
|
||||
"field": "name",
|
||||
"message": "名称不能为空"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 分页格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"items": [],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_pages": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、认证接口
|
||||
|
||||
### 2.1 用户登录
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
POST /auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "password123"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 刷新Token
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
POST /auth/refresh
|
||||
Authorization: Bearer {refresh_token}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"expires_in": 3600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、用户管理接口
|
||||
|
||||
### 3.1 获取用户列表
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
GET /users?page=1&page_size=20&status=active
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"role": "admin",
|
||||
"status": "active",
|
||||
"created_at": "2026-03-31T10:00:00Z",
|
||||
"updated_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 创建用户
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
POST /users
|
||||
Authorization: Bearer {access_token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "newuser",
|
||||
"email": "newuser@example.com",
|
||||
"password": "password123",
|
||||
"role": "engineer"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"username": "newuser",
|
||||
"email": "newuser@example.com",
|
||||
"role": "engineer",
|
||||
"status": "active",
|
||||
"created_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、产品管理接口
|
||||
|
||||
### 4.1 获取产品列表
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
GET /products?page=1&page_size=20&category_id=1
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
### 4.2 创建产品
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
POST /products
|
||||
Authorization: Bearer {access_token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": "P001",
|
||||
"name": "产品名称",
|
||||
"description": "产品描述",
|
||||
"category_id": 1,
|
||||
"status": "draft"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、BOM管理接口
|
||||
|
||||
### 5.1 获取BOM列表
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
GET /boms?product_id=1
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
### 5.2 创建BOM
|
||||
|
||||
**请求:**
|
||||
|
||||
```
|
||||
POST /boms
|
||||
Authorization: Bearer {access_token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"product_id": 1,
|
||||
"version": "1.0",
|
||||
"items": [
|
||||
{
|
||||
"material_code": "M001",
|
||||
"quantity": 10,
|
||||
"unit": "pcs"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、错误码定义
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 0 | 成功 |
|
||||
| 40001 | 参数错误 |
|
||||
| 40002 | 资源不存在 |
|
||||
| 40003 | 资源已存在 |
|
||||
| 40101 | 未授权 |
|
||||
| 40102 | Token过期 |
|
||||
| 40301 | 权限不足 |
|
||||
| 50001 | 服务器内部错误 |
|
||||
|
||||
---
|
||||
|
||||
## 七、API 版本管理
|
||||
|
||||
- v1: 当前版本
|
||||
- v2: 开发中
|
||||
|
||||
版本通过URL路径控制:`/api/v1/...`
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 18:06_
|
||||
_维护人:笔杆子 (creator)_
|
||||
742
api/PLM-API接口文档-V2.md
Normal file
742
api/PLM-API接口文档-V2.md
Normal file
@@ -0,0 +1,742 @@
|
||||
# PLM 系统 API 接口文档
|
||||
|
||||
> **版本**:V2.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子 (creator)
|
||||
> **状态**:已发布
|
||||
> **基础URL**:`https://api.plm.example.com/v1`
|
||||
|
||||
---
|
||||
|
||||
## 一、概述
|
||||
|
||||
### 1.1 API 设计规范
|
||||
|
||||
| 规范 | 说明 |
|
||||
|------|------|
|
||||
| 协议 | HTTPS |
|
||||
| 数据格式 | JSON |
|
||||
| 字符编码 | UTF-8 |
|
||||
| 认证方式 | Bearer Token (JWT) |
|
||||
| 版本控制 | URL路径 `/v1/` |
|
||||
|
||||
### 1.2 HTTP 方法
|
||||
|
||||
| 方法 | 用途 |
|
||||
|------|------|
|
||||
| GET | 查询资源 |
|
||||
| POST | 创建资源 |
|
||||
| PUT | 全量更新 |
|
||||
| PATCH | 部分更新 |
|
||||
| DELETE | 删除资源 |
|
||||
|
||||
---
|
||||
|
||||
## 二、通用响应格式
|
||||
|
||||
### 2.1 成功响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": { },
|
||||
"timestamp": "2026-03-31T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 40001,
|
||||
"message": "参数错误",
|
||||
"errors": [
|
||||
{
|
||||
"field": "name",
|
||||
"message": "名称不能为空"
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-03-31T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 分页响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"items": [],
|
||||
"pagination": {
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_pages": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、认证接口 (Auth)
|
||||
|
||||
### 3.1 用户登录
|
||||
|
||||
**POST** `/auth/login`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "Admin@123456"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 刷新Token
|
||||
|
||||
**POST** `/auth/refresh`
|
||||
|
||||
**Header:**
|
||||
```
|
||||
Authorization: Bearer {refresh_token}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"expires_in": 3600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 用户登出
|
||||
|
||||
**POST** `/auth/logout`
|
||||
|
||||
**Header:**
|
||||
```
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "登出成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 修改密码
|
||||
|
||||
**PUT** `/auth/password`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"old_password": "Admin@123456",
|
||||
"new_password": "NewPass@123"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、用户管理接口 (Users)
|
||||
|
||||
### 4.1 获取用户列表
|
||||
|
||||
**GET** `/users`
|
||||
|
||||
**查询参数:**
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| page_size | int | 否 | 每页数量,默认20 |
|
||||
| status | string | 否 | 状态筛选 |
|
||||
| role | string | 否 | 角色筛选 |
|
||||
| keyword | string | 否 | 关键词搜索 |
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"phone": "13800138000",
|
||||
"role": "admin",
|
||||
"status": "active",
|
||||
"department_id": 1,
|
||||
"created_at": "2026-03-01T10:00:00Z",
|
||||
"updated_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 获取用户详情
|
||||
|
||||
**GET** `/users/{user_id}`
|
||||
|
||||
### 4.3 创建用户
|
||||
|
||||
**POST** `/users`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"username": "newuser",
|
||||
"email": "newuser@example.com",
|
||||
"phone": "13800138001",
|
||||
"password": "User@123456",
|
||||
"role": "engineer",
|
||||
"department_id": 2
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 更新用户
|
||||
|
||||
**PUT** `/users/{user_id}`
|
||||
|
||||
### 4.5 删除用户
|
||||
|
||||
**DELETE** `/users/{user_id}`
|
||||
|
||||
### 4.6 修改用户状态
|
||||
|
||||
**PATCH** `/users/{user_id}/status`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"status": "inactive"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、产品管理接口 (Products)
|
||||
|
||||
### 5.1 获取产品列表
|
||||
|
||||
**GET** `/products`
|
||||
|
||||
**查询参数:**
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码 |
|
||||
| page_size | int | 否 | 每页数量 |
|
||||
| category_id | int | 否 | 分类ID |
|
||||
| status | string | 否 | 状态 |
|
||||
| keyword | string | 否 | 关键词 |
|
||||
|
||||
### 5.2 获取产品详情
|
||||
|
||||
**GET** `/products/{product_id}`
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"code": "P001",
|
||||
"name": "产品名称",
|
||||
"description": "产品描述",
|
||||
"category": {
|
||||
"id": 1,
|
||||
"name": "分类名称"
|
||||
},
|
||||
"status": "released",
|
||||
"version": "1.0.0",
|
||||
"ai_analysis_status": "completed",
|
||||
"ai_recommendation": "建议内容",
|
||||
"created_at": "2026-03-01T10:00:00Z",
|
||||
"updated_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 创建产品
|
||||
|
||||
**POST** `/products`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"code": "P001",
|
||||
"name": "产品名称",
|
||||
"description": "产品描述",
|
||||
"category_id": 1,
|
||||
"status": "draft"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 更新产品
|
||||
|
||||
**PUT** `/products/{product_id}`
|
||||
|
||||
### 5.5 删除产品
|
||||
|
||||
**DELETE** `/products/{product_id}`
|
||||
|
||||
### 5.6 产品版本管理
|
||||
|
||||
**GET** `/products/{product_id}/versions`
|
||||
|
||||
**POST** `/products/{product_id}/versions`
|
||||
|
||||
### 5.7 AI智能分类
|
||||
|
||||
**POST** `/products/{product_id}/ai-classify`
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"suggested_category": {
|
||||
"id": 5,
|
||||
"name": "建议分类",
|
||||
"confidence": 0.92
|
||||
},
|
||||
"similar_products": [
|
||||
{
|
||||
"id": 10,
|
||||
"name": "相似产品",
|
||||
"similarity": 0.85
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、BOM管理接口 (BOMs)
|
||||
|
||||
### 6.1 获取BOM列表
|
||||
|
||||
**GET** `/boms`
|
||||
|
||||
### 6.2 获取BOM详情
|
||||
|
||||
**GET** `/boms/{bom_id}`
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"product_id": 1,
|
||||
"version": "1.0",
|
||||
"status": "released",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"material_code": "M001",
|
||||
"material_name": "物料名称",
|
||||
"quantity": 10,
|
||||
"unit": "pcs",
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"ai_recommendation": "优化建议"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 创建BOM
|
||||
|
||||
**POST** `/boms`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"product_id": 1,
|
||||
"version": "1.0",
|
||||
"items": [
|
||||
{
|
||||
"material_code": "M001",
|
||||
"quantity": 10,
|
||||
"unit": "pcs"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4 BOM展开
|
||||
|
||||
**GET** `/boms/{bom_id}/expand`
|
||||
|
||||
**查询参数:**
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| level | int | 展开层级,-1为全部展开 |
|
||||
|
||||
### 6.5 BOM对比
|
||||
|
||||
**POST** `/boms/compare`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"bom_id_1": 1,
|
||||
"bom_id_2": 2
|
||||
}
|
||||
```
|
||||
|
||||
### 6.6 AI优化建议
|
||||
|
||||
**POST** `/boms/{bom_id}/ai-optimize`
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"optimizations": [
|
||||
{
|
||||
"type": "material_substitution",
|
||||
"original": "M001",
|
||||
"suggested": "M002",
|
||||
"reason": "成本降低15%",
|
||||
"confidence": 0.88
|
||||
}
|
||||
],
|
||||
"similar_boms": [
|
||||
{
|
||||
"id": 5,
|
||||
"product_name": "相似产品BOM",
|
||||
"similarity": 0.82
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、文档管理接口 (Documents)
|
||||
|
||||
### 7.1 获取文档列表
|
||||
|
||||
**GET** `/documents`
|
||||
|
||||
### 7.2 上传文档
|
||||
|
||||
**POST** `/documents/upload`
|
||||
|
||||
**请求体:** multipart/form-data
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| file | file | 文件 |
|
||||
| product_id | int | 关联产品ID |
|
||||
| category | string | 文档分类 |
|
||||
|
||||
### 7.3 下载文档
|
||||
|
||||
**GET** `/documents/{doc_id}/download`
|
||||
|
||||
### 7.4 文档版本历史
|
||||
|
||||
**GET** `/documents/{doc_id}/versions`
|
||||
|
||||
### 7.5 AI智能标签
|
||||
|
||||
**POST** `/documents/{doc_id}/ai-tag`
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"tags": ["技术文档", "设计规范", "API"],
|
||||
"summary": "文档摘要内容..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、变更管理接口 (Changes)
|
||||
|
||||
### 8.1 获取变更列表
|
||||
|
||||
**GET** `/changes`
|
||||
|
||||
### 8.2 创建变更申请 (ECR)
|
||||
|
||||
**POST** `/changes`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"type": "design_change",
|
||||
"title": "变更标题",
|
||||
"description": "变更描述",
|
||||
"reason": "变更原因",
|
||||
"product_ids": [1, 2],
|
||||
"attachments": []
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 变更审批
|
||||
|
||||
**POST** `/changes/{change_id}/approve`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"action": "approve",
|
||||
"comment": "审批意见"
|
||||
}
|
||||
```
|
||||
|
||||
### 8.4 AI风险预测
|
||||
|
||||
**POST** `/changes/{change_id}/ai-risk`
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"risk_level": "medium",
|
||||
"risk_score": 0.65,
|
||||
"affected_items": [
|
||||
{
|
||||
"type": "bom",
|
||||
"id": 1,
|
||||
"impact": "物料M001数量需调整"
|
||||
}
|
||||
],
|
||||
"recommendations": [
|
||||
"建议同步更新工艺路线",
|
||||
"需通知采购部门"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、搜索接口 (Search)
|
||||
|
||||
### 9.1 全局搜索
|
||||
|
||||
**GET** `/search`
|
||||
|
||||
**查询参数:**
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| q | string | 搜索关键词 |
|
||||
| type | string | 资源类型 |
|
||||
| page | int | 页码 |
|
||||
|
||||
### 9.2 AI智能搜索
|
||||
|
||||
**POST** `/search/ai`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"query": "查找所有使用物料M001的产品",
|
||||
"context": {}
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"sql": "SELECT * FROM products WHERE id IN (SELECT product_id FROM boms WHERE material_code = 'M001')",
|
||||
"results": [...],
|
||||
"explanation": "已为您查找所有BOM中包含物料M001的产品"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、工作流接口 (Workflows)
|
||||
|
||||
### 10.1 获取工作流定义列表
|
||||
|
||||
**GET** `/workflows/definitions`
|
||||
|
||||
### 10.2 启动工作流实例
|
||||
|
||||
**POST** `/workflows/instances`
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"definition_id": "approval_flow",
|
||||
"business_key": "ECR-001",
|
||||
"variables": {
|
||||
"approver": "manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 10.3 获取工作流实例详情
|
||||
|
||||
**GET** `/workflows/instances/{instance_id}`
|
||||
|
||||
### 10.4 完成任务
|
||||
|
||||
**POST** `/workflows/tasks/{task_id}/complete`
|
||||
|
||||
---
|
||||
|
||||
## 十一、错误码定义
|
||||
|
||||
### 11.1 通用错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 0 | 成功 |
|
||||
| 40001 | 参数错误 |
|
||||
| 40002 | 资源不存在 |
|
||||
| 40003 | 资源已存在 |
|
||||
| 40004 | 操作不允许 |
|
||||
|
||||
### 11.2 认证错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 40101 | 未授权 |
|
||||
| 40102 | Token过期 |
|
||||
| 40103 | Token无效 |
|
||||
| 40104 | 密码错误 |
|
||||
|
||||
### 11.3 权限错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 40301 | 权限不足 |
|
||||
| 40302 | 账户被禁用 |
|
||||
|
||||
### 11.4 服务端错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 50001 | 服务器内部错误 |
|
||||
| 50002 | 数据库错误 |
|
||||
| 50003 | 第三方服务错误 |
|
||||
|
||||
---
|
||||
|
||||
## 十二、API调用示例
|
||||
|
||||
### 12.1 cURL示例
|
||||
|
||||
```bash
|
||||
# 登录获取Token
|
||||
curl -X POST https://api.plm.example.com/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"Admin@123456"}'
|
||||
|
||||
# 获取产品列表
|
||||
curl -X GET https://api.plm.example.com/v1/products \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
|
||||
|
||||
# 创建产品
|
||||
curl -X POST https://api.plm.example.com/v1/products \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"code":"P001","name":"产品名称"}'
|
||||
```
|
||||
|
||||
### 12.2 Python示例
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = "https://api.plm.example.com/v1"
|
||||
|
||||
# 登录
|
||||
response = requests.post(f"{BASE_URL}/auth/login", json={
|
||||
"username": "admin",
|
||||
"password": "Admin@123456"
|
||||
})
|
||||
token = response.json()["data"]["access_token"]
|
||||
|
||||
# 获取产品列表
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
response = requests.get(f"{BASE_URL}/products", headers=headers)
|
||||
products = response.json()["data"]["items"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十三、附录
|
||||
|
||||
### 13.1 状态枚举
|
||||
|
||||
**用户状态:**
|
||||
- `active` - 激活
|
||||
- `inactive` - 未激活
|
||||
- `suspended` - 已停用
|
||||
- `pending` - 待审核
|
||||
|
||||
**产品状态:**
|
||||
- `draft` - 草稿
|
||||
- `released` - 发布
|
||||
- `frozen` - 冻结
|
||||
- `obsolete` - 退役
|
||||
|
||||
**BOM状态:**
|
||||
- `draft` - 草稿
|
||||
- `frozen` - 冻结
|
||||
- `released` - 发布
|
||||
|
||||
**变更状态:**
|
||||
- `draft` - 草稿
|
||||
- `submitted` - 已提交
|
||||
- `approved` - 已批准
|
||||
- `rejected` - 已拒绝
|
||||
- `implemented` - 已执行
|
||||
|
||||
### 13.2 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更内容 |
|
||||
|------|------|----------|
|
||||
| V2.0 | 2026-03-31 | 新增AI接口、完善业务接口 |
|
||||
| V1.0 | 2026-03-31 | 初始版本 |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 20:15_
|
||||
_维护人:笔杆子 (creator)_
|
||||
873
api/产品服务API文档-V2.md
Normal file
873
api/产品服务API文档-V2.md
Normal file
@@ -0,0 +1,873 @@
|
||||
# 产品服务 API 接口文档
|
||||
|
||||
> **版本**:V2.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子 (creator)
|
||||
> **状态**:已发布
|
||||
> **微服务**:plm-product-service
|
||||
> **基础URL**:`https://api.plm.example.com/v1`
|
||||
|
||||
---
|
||||
|
||||
## 一、服务概述
|
||||
|
||||
### 1.1 服务定位
|
||||
|
||||
产品服务负责管理产品全生命周期数据,是PLM系统的核心基础服务。
|
||||
|
||||
**核心职责:**
|
||||
- 产品信息管理(CRUD)
|
||||
- 产品版本控制
|
||||
- 产品分类管理
|
||||
- 产品状态管理
|
||||
- AI智能分类与推荐
|
||||
|
||||
### 1.2 服务端口
|
||||
|
||||
| 协议 | 端口 |
|
||||
|------|------|
|
||||
| HTTP | 8002 |
|
||||
| gRPC | 50052 |
|
||||
|
||||
---
|
||||
|
||||
## 二、数据模型
|
||||
|
||||
### 2.1 产品主表 (products)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER | 主键 |
|
||||
| code | VARCHAR(50) | 产品编码(唯一) |
|
||||
| name | VARCHAR(200) | 产品名称 |
|
||||
| description | TEXT | 产品描述 |
|
||||
| category_id | INTEGER | 分类ID |
|
||||
| type | VARCHAR(50) | 产品类型 |
|
||||
| status | VARCHAR(20) | 状态 |
|
||||
| unit | VARCHAR(20) | 计量单位 |
|
||||
| weight | DECIMAL(10,2) | 重量 |
|
||||
| specifications | JSONB | 规格参数 |
|
||||
| custom_attributes | JSONB | 自定义属性 |
|
||||
| ai_analysis_status | VARCHAR(20) | AI分析状态 |
|
||||
| ai_recommendation | TEXT | AI推荐内容 |
|
||||
| ai_confidence_score | FLOAT | AI置信度 |
|
||||
| embedding_vector | VECTOR(1536) | 向量嵌入 |
|
||||
| created_by | INTEGER | 创建人 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | 更新时间 |
|
||||
|
||||
### 2.2 产品版本表 (product_versions)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER | 主键 |
|
||||
| product_id | INTEGER | 产品ID |
|
||||
| version | VARCHAR(20) | 版本号 |
|
||||
| change_log | TEXT | 变更日志 |
|
||||
| status | VARCHAR(20) | 状态 |
|
||||
| ai_change_analysis | TEXT | AI变更分析 |
|
||||
| released_at | TIMESTAMP | 发布时间 |
|
||||
| released_by | INTEGER | 发布人 |
|
||||
|
||||
### 2.3 产品分类表 (product_categories)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER | 主键 |
|
||||
| parent_id | INTEGER | 父分类ID |
|
||||
| code | VARCHAR(50) | 分类编码 |
|
||||
| name | VARCHAR(100) | 分类名称 |
|
||||
| level | INTEGER | 层级 |
|
||||
| path | VARCHAR(500) | 路径 |
|
||||
| ai_classification_rules | JSONB | AI分类规则 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 三、产品管理接口
|
||||
|
||||
### 3.1 获取产品列表
|
||||
|
||||
```
|
||||
GET /api/v1/products
|
||||
```
|
||||
|
||||
**请求头:**
|
||||
```
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| page_size | int | 否 | 每页数量,默认20,最大100 |
|
||||
| keyword | string | 否 | 搜索关键词(编码/名称) |
|
||||
| category_id | int | 否 | 分类ID |
|
||||
| status | string | 否 | 状态筛选 |
|
||||
| type | string | 否 | 类型筛选 |
|
||||
| sort_by | string | 否 | 排序字段(created_at/updated_at/name) |
|
||||
| sort_order | string | 否 | 排序方向(asc/desc) |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"code": "P001",
|
||||
"name": "智能电机A型",
|
||||
"description": "高效节能智能电机",
|
||||
"category": {
|
||||
"id": 5,
|
||||
"name": "电机类"
|
||||
},
|
||||
"type": "standard",
|
||||
"status": "released",
|
||||
"unit": "台",
|
||||
"version": "2.0",
|
||||
"ai_analysis_status": "completed",
|
||||
"created_at": "2026-03-01T10:00:00Z",
|
||||
"updated_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": 150,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_pages": 8
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-03-31T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 获取产品详情
|
||||
|
||||
```
|
||||
GET /api/v1/products/{product_id}
|
||||
```
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| product_id | int | 是 | 产品ID |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"code": "P001",
|
||||
"name": "智能电机A型",
|
||||
"description": "高效节能智能电机,功率范围1-100kW",
|
||||
"category": {
|
||||
"id": 5,
|
||||
"name": "电机类",
|
||||
"path": "设备/动力设备/电机类"
|
||||
},
|
||||
"type": "standard",
|
||||
"status": "released",
|
||||
"unit": "台",
|
||||
"weight": 150.5,
|
||||
"specifications": {
|
||||
"power": "50kW",
|
||||
"voltage": "380V",
|
||||
"speed": "1500rpm"
|
||||
},
|
||||
"custom_attributes": {
|
||||
"brand": "自主品牌",
|
||||
"warranty": "2年"
|
||||
},
|
||||
"version": "2.0",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.0",
|
||||
"status": "obsolete",
|
||||
"released_at": "2026-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "2.0",
|
||||
"status": "released",
|
||||
"released_at": "2026-03-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"ai_analysis_status": "completed",
|
||||
"ai_recommendation": "建议分类:电机类(置信度92%)。相似产品:智能电机B型、高效电机C型",
|
||||
"ai_confidence_score": 0.92,
|
||||
"created_by": {
|
||||
"id": 1,
|
||||
"name": "admin"
|
||||
},
|
||||
"created_at": "2026-03-01T10:00:00Z",
|
||||
"updated_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 创建产品
|
||||
|
||||
```
|
||||
POST /api/v1/products
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "P002",
|
||||
"name": "智能电机B型",
|
||||
"description": "新型高效智能电机",
|
||||
"category_id": 5,
|
||||
"type": "standard",
|
||||
"unit": "台",
|
||||
"weight": 120.0,
|
||||
"specifications": {
|
||||
"power": "30kW",
|
||||
"voltage": "380V",
|
||||
"speed": "3000rpm"
|
||||
},
|
||||
"custom_attributes": {
|
||||
"brand": "自主品牌",
|
||||
"warranty": "3年"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"code": "P002",
|
||||
"name": "智能电机B型",
|
||||
"status": "draft",
|
||||
"ai_analysis_status": "pending",
|
||||
"created_at": "2026-03-31T12:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 更新产品
|
||||
|
||||
```
|
||||
PUT /api/v1/products/{product_id}
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "智能电机B型(升级版)",
|
||||
"description": "升级版高效智能电机",
|
||||
"weight": 125.0
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 删除产品
|
||||
|
||||
```
|
||||
DELETE /api/v1/products/{product_id}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "删除成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6 批量导入产品
|
||||
|
||||
```
|
||||
POST /api/v1/products/import
|
||||
```
|
||||
|
||||
**请求体:** multipart/form-data
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| file | file | Excel文件(.xlsx) |
|
||||
| update_existing | boolean | 是否更新已存在产品 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"total": 100,
|
||||
"success": 95,
|
||||
"failed": 5,
|
||||
"errors": [
|
||||
{
|
||||
"row": 10,
|
||||
"code": "P010",
|
||||
"error": "编码已存在"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.7 批量导出产品
|
||||
|
||||
```
|
||||
GET /api/v1/products/export
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| ids | string | 产品ID列表,逗号分隔 |
|
||||
| category_id | int | 按分类导出 |
|
||||
| status | string | 按状态导出 |
|
||||
| format | string | 格式(xlsx/csv) |
|
||||
|
||||
---
|
||||
|
||||
## 四、产品版本接口
|
||||
|
||||
### 4.1 获取产品版本列表
|
||||
|
||||
```
|
||||
GET /api/v1/products/{product_id}/versions
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"version": "1.0",
|
||||
"change_log": "初始版本",
|
||||
"status": "obsolete",
|
||||
"released_at": "2026-01-01T00:00:00Z",
|
||||
"released_by": {
|
||||
"id": 1,
|
||||
"name": "admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"version": "2.0",
|
||||
"change_log": "性能优化,功率提升20%",
|
||||
"status": "released",
|
||||
"ai_change_analysis": "主要变更:功率参数从40kW提升到50kW,预计影响下游BOM中相关组件选型",
|
||||
"released_at": "2026-03-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 创建新版本
|
||||
|
||||
```
|
||||
POST /api/v1/products/{product_id}/versions
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "3.0",
|
||||
"change_log": "增加智能监控功能",
|
||||
"specifications": {
|
||||
"power": "55kW",
|
||||
"voltage": "380V",
|
||||
"speed": "1500rpm",
|
||||
"monitoring": "IoT智能监控"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 发布版本
|
||||
|
||||
```
|
||||
POST /api/v1/products/{product_id}/versions/{version_id}/release
|
||||
```
|
||||
|
||||
### 4.4 版本对比
|
||||
|
||||
```
|
||||
GET /api/v1/products/{product_id}/versions/compare
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| version1 | string | 版本1 |
|
||||
| version2 | string | 版本2 |
|
||||
|
||||
---
|
||||
|
||||
## 五、产品分类接口
|
||||
|
||||
### 5.1 获取分类树
|
||||
|
||||
```
|
||||
GET /api/v1/products/categories/tree
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 0,
|
||||
"name": "全部",
|
||||
"children": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "设备",
|
||||
"children": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "动力设备",
|
||||
"children": [
|
||||
{
|
||||
"id": 5,
|
||||
"name": "电机类",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 获取分类详情
|
||||
|
||||
```
|
||||
GET /api/v1/products/categories/{category_id}
|
||||
```
|
||||
|
||||
### 5.3 创建分类
|
||||
|
||||
```
|
||||
POST /api/v1/products/categories
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"parent_id": 5,
|
||||
"code": "MOTOR-AC",
|
||||
"name": "交流电机"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 更新分类
|
||||
|
||||
```
|
||||
PUT /api/v1/products/categories/{category_id}
|
||||
```
|
||||
|
||||
### 5.5 删除分类
|
||||
|
||||
```
|
||||
DELETE /api/v1/products/categories/{category_id}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、产品状态接口
|
||||
|
||||
### 6.1 获取状态列表
|
||||
|
||||
```
|
||||
GET /api/v1/products/statuses
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": [
|
||||
{
|
||||
"code": "draft",
|
||||
"name": "草稿",
|
||||
"description": "新建产品,未发布"
|
||||
},
|
||||
{
|
||||
"code": "released",
|
||||
"name": "已发布",
|
||||
"description": "已正式发布"
|
||||
},
|
||||
{
|
||||
"code": "frozen",
|
||||
"name": "已冻结",
|
||||
"description": "暂停使用"
|
||||
},
|
||||
{
|
||||
"code": "obsolete",
|
||||
"name": "已废弃",
|
||||
"description": "不再使用"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 变更状态
|
||||
|
||||
```
|
||||
PATCH /api/v1/products/{product_id}/status
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "released",
|
||||
"reason": "产品已通过测试,正式发布"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、AI智能接口
|
||||
|
||||
### 7.1 AI智能分类
|
||||
|
||||
```
|
||||
POST /api/v1/products/{product_id}/ai-classify
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"suggested_category": {
|
||||
"id": 5,
|
||||
"name": "电机类",
|
||||
"path": "设备/动力设备/电机类",
|
||||
"confidence": 0.92
|
||||
},
|
||||
"alternative_categories": [
|
||||
{
|
||||
"id": 6,
|
||||
"name": "发电机类",
|
||||
"confidence": 0.15
|
||||
}
|
||||
],
|
||||
"classification_reason": "根据产品名称'智能电机'和规格参数,判断属于电机类"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 AI相似产品推荐
|
||||
|
||||
```
|
||||
GET /api/v1/products/{product_id}/ai-similar
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"similar_products": [
|
||||
{
|
||||
"id": 3,
|
||||
"code": "P003",
|
||||
"name": "智能电机B型",
|
||||
"similarity": 0.88,
|
||||
"match_details": {
|
||||
"specifications_match": 0.95,
|
||||
"category_match": 1.0,
|
||||
"name_similarity": 0.85
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 AI智能补全
|
||||
|
||||
```
|
||||
POST /api/v1/products/ai-autocomplete
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"field": "specifications",
|
||||
"partial_data": {
|
||||
"power": "50kW",
|
||||
"voltage": "380V"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"suggestions": {
|
||||
"speed": ["1500rpm", "3000rpm"],
|
||||
"frequency": "50Hz",
|
||||
"efficiency": "IE3"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.4 AI智能搜索
|
||||
|
||||
```
|
||||
POST /api/v1/products/ai-search
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "功率在30-50kW之间的三相电机",
|
||||
"filters": {}
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"sql_equivalent": "SELECT * FROM products WHERE specifications->>'power' BETWEEN '30kW' AND '50kW' AND category_id = 5",
|
||||
"results": [...],
|
||||
"explanation": "已为您找到功率在30-50kW之间的电机类产品"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、属性模板接口
|
||||
|
||||
### 8.1 获取属性模板列表
|
||||
|
||||
```
|
||||
GET /api/v1/products/attribute-templates
|
||||
```
|
||||
|
||||
### 8.2 获取模板详情
|
||||
|
||||
```
|
||||
GET /api/v1/products/attribute-templates/{template_id}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "电机属性模板",
|
||||
"category_id": 5,
|
||||
"attributes": [
|
||||
{
|
||||
"name": "power",
|
||||
"label": "功率",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"unit": "kW",
|
||||
"validation": "^\\d+kW$"
|
||||
},
|
||||
{
|
||||
"name": "voltage",
|
||||
"label": "电压",
|
||||
"type": "select",
|
||||
"required": true,
|
||||
"options": ["220V", "380V", "660V"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 创建属性模板
|
||||
|
||||
```
|
||||
POST /api/v1/products/attribute-templates
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、gRPC接口
|
||||
|
||||
### 9.1 Proto定义
|
||||
|
||||
```protobuf
|
||||
// proto/product.proto
|
||||
syntax = "proto3";
|
||||
|
||||
package plm.product;
|
||||
|
||||
service ProductService {
|
||||
rpc GetProduct(GetProductRequest) returns (ProductResponse);
|
||||
rpc ListProducts(ListProductsRequest) returns (ListProductsResponse);
|
||||
rpc CreateProduct(CreateProductRequest) returns (ProductResponse);
|
||||
rpc UpdateProduct(UpdateProductRequest) returns (ProductResponse);
|
||||
rpc DeleteProduct(DeleteProductRequest) returns (DeleteProductResponse);
|
||||
|
||||
// AI流式接口
|
||||
rpc AIClassify(AIClassifyRequest) returns (stream AIClassifyResponse);
|
||||
rpc FindSimilar(SimilarProductsRequest) returns (SimilarProductsResponse);
|
||||
}
|
||||
|
||||
message Product {
|
||||
int32 id = 1;
|
||||
string code = 2;
|
||||
string name = 3;
|
||||
string description = 4;
|
||||
int32 category_id = 5;
|
||||
string status = 6;
|
||||
map<string, string> specifications = 7;
|
||||
}
|
||||
|
||||
message GetProductRequest {
|
||||
int32 product_id = 1;
|
||||
}
|
||||
|
||||
message ProductResponse {
|
||||
Product product = 1;
|
||||
}
|
||||
|
||||
message ListProductsRequest {
|
||||
int32 page = 1;
|
||||
int32 page_size = 2;
|
||||
string keyword = 3;
|
||||
int32 category_id = 4;
|
||||
}
|
||||
|
||||
message ListProductsResponse {
|
||||
repeated Product items = 1;
|
||||
int32 total = 2;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、错误码
|
||||
|
||||
### 10.1 产品相关错误码
|
||||
|
||||
| 错误码 | HTTP状态码 | 说明 |
|
||||
|--------|------------|------|
|
||||
| 40001 | 400 | 参数错误 |
|
||||
| 40002 | 404 | 产品不存在 |
|
||||
| 40003 | 409 | 产品编码已存在 |
|
||||
| 40004 | 400 | 分类不存在 |
|
||||
| 40005 | 400 | 状态转换不允许 |
|
||||
|
||||
### 10.2 AI相关错误码
|
||||
|
||||
| 错误码 | HTTP状态码 | 说明 |
|
||||
|--------|------------|------|
|
||||
| 50101 | 500 | AI服务不可用 |
|
||||
| 50102 | 500 | AI分析超时 |
|
||||
| 50103 | 500 | 向量嵌入失败 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、调用示例
|
||||
|
||||
### 11.1 Python示例
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = "https://api.plm.example.com/v1"
|
||||
TOKEN = "your-access-token"
|
||||
|
||||
headers = {"Authorization": f"Bearer {TOKEN}"}
|
||||
|
||||
# 获取产品列表
|
||||
response = requests.get(f"{BASE_URL}/products", headers=headers)
|
||||
products = response.json()["data"]["items"]
|
||||
|
||||
# 创建产品
|
||||
new_product = {
|
||||
"code": "P003",
|
||||
"name": "智能电机C型",
|
||||
"category_id": 5
|
||||
}
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/products",
|
||||
headers=headers,
|
||||
json=new_product
|
||||
)
|
||||
|
||||
# AI分类
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/products/{product_id}/ai-classify",
|
||||
headers=headers
|
||||
)
|
||||
```
|
||||
|
||||
### 11.2 cURL示例
|
||||
|
||||
```bash
|
||||
# 获取产品列表
|
||||
curl -X GET "https://api.plm.example.com/v1/products?page=1&page_size=20" \
|
||||
-H "Authorization: Bearer your-token"
|
||||
|
||||
# 创建产品
|
||||
curl -X POST "https://api.plm.example.com/v1/products" \
|
||||
-H "Authorization: Bearer your-token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"code":"P003","name":"智能电机C型","category_id":5}'
|
||||
|
||||
# AI智能分类
|
||||
curl -X POST "https://api.plm.example.com/v1/products/1/ai-classify" \
|
||||
-H "Authorization: Bearer your-token"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、版本历史
|
||||
|
||||
| 版本 | 日期 | 变更内容 |
|
||||
|------|------|----------|
|
||||
| V2.0 | 2026-03-31 | 新增AI接口、版本管理接口 |
|
||||
| V1.0 | 2026-03-01 | 初始版本 |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 20:40_
|
||||
_维护人:笔杆子 (creator)_
|
||||
774
architecture/BOM服务技术文档.md
Normal file
774
architecture/BOM服务技术文档.md
Normal file
@@ -0,0 +1,774 @@
|
||||
# BOM 服务技术文档
|
||||
|
||||
> **版本**:V1.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子 (creator)
|
||||
> **状态**:已发布
|
||||
> **微服务**:plm-bom-service
|
||||
|
||||
---
|
||||
|
||||
## 一、服务概述
|
||||
|
||||
### 1.1 服务定位
|
||||
|
||||
BOM(Bill of Materials)服务负责管理产品的物料清单,是PLM系统的核心服务之一。
|
||||
|
||||
**核心职责:**
|
||||
- BOM创建与管理
|
||||
- BOM层级结构维护
|
||||
- BOM版本控制
|
||||
- BOM展开与对比分析
|
||||
- 物料需求计算
|
||||
- AI智能优化建议
|
||||
|
||||
### 1.2 服务架构
|
||||
|
||||
```
|
||||
plm-bom-service/
|
||||
├── api/ # API层
|
||||
│ ├── bom_router.py # BOM路由
|
||||
│ └── bom_item_router.py # BOM明细路由
|
||||
├── services/ # 业务层
|
||||
│ ├── bom_service.py # BOM业务逻辑
|
||||
│ └── bom_engine.py # C++引擎绑定
|
||||
├── models/ # 数据层
|
||||
│ ├── bom.py # BOM主表
|
||||
│ └── bom_item.py # BOM明细表
|
||||
├── schemas/ # 数据验证
|
||||
│ └── bom_schemas.py
|
||||
└── ai/ # AI模块
|
||||
├── bom_optimizer.py # BOM优化
|
||||
└── similarity.py # 相似检测
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、数据模型
|
||||
|
||||
### 2.1 BOM主表 (boms)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER | 主键 |
|
||||
| product_id | INTEGER | 产品ID(外键) |
|
||||
| code | VARCHAR(50) | BOM编码 |
|
||||
| name | VARCHAR(200) | BOM名称 |
|
||||
| version | VARCHAR(20) | 版本号 |
|
||||
| type | VARCHAR(20) | BOM类型 |
|
||||
| status | VARCHAR(20) | 状态 |
|
||||
| parent_bom_id | INTEGER | 父BOM ID |
|
||||
| effective_date | DATE | 生效日期 |
|
||||
| expiry_date | DATE | 失效日期 |
|
||||
| ai_analysis_status | VARCHAR(20) | AI分析状态 |
|
||||
| ai_recommendation | TEXT | AI推荐内容 |
|
||||
| ai_confidence_score | FLOAT | AI置信度 |
|
||||
| embedding_vector | VECTOR(1536) | 向量嵌入 |
|
||||
| created_by | INTEGER | 创建人 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | 更新时间 |
|
||||
|
||||
### 2.2 BOM明细表 (bom_items)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER | 主键 |
|
||||
| bom_id | INTEGER | BOM ID(外键) |
|
||||
| parent_item_id | INTEGER | 父项ID |
|
||||
| level | INTEGER | 层级 |
|
||||
| sequence | INTEGER | 序号 |
|
||||
| material_id | INTEGER | 物料ID |
|
||||
| material_code | VARCHAR(50) | 物料编码 |
|
||||
| material_name | VARCHAR(200) | 物料名称 |
|
||||
| quantity | DECIMAL(10,4) | 数量 |
|
||||
| unit | VARCHAR(20) | 单位 |
|
||||
| scrap_rate | DECIMAL(5,2) | 损耗率 |
|
||||
| substitute_material_id | INTEGER | 替代物料ID |
|
||||
| effective_date | DATE | 生效日期 |
|
||||
| remark | TEXT | 备注 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
|
||||
### 2.3 BOM版本差异表 (bom_version_diffs)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER | 主键 |
|
||||
| bom_id | INTEGER | BOM ID |
|
||||
| old_version | VARCHAR(20) | 旧版本 |
|
||||
| new_version | VARCHAR(20) | 新版本 |
|
||||
| diff_type | VARCHAR(20) | 差异类型 |
|
||||
| diff_details | JSONB | 差异详情 |
|
||||
| ai_impact_analysis | TEXT | AI影响分析 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 三、API接口
|
||||
|
||||
### 3.1 BOM管理接口
|
||||
|
||||
#### 3.1.1 获取BOM列表
|
||||
|
||||
```
|
||||
GET /api/v1/boms
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| product_id | int | 否 | 产品ID |
|
||||
| status | string | 否 | 状态筛选 |
|
||||
| type | string | 否 | 类型筛选 |
|
||||
| keyword | string | 否 | 关键词 |
|
||||
| page | int | 否 | 页码 |
|
||||
| page_size | int | 否 | 每页数量 |
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"product_id": 1,
|
||||
"code": "BOM-001",
|
||||
"name": "产品A物料清单",
|
||||
"version": "1.0",
|
||||
"type": "manufacturing",
|
||||
"status": "released",
|
||||
"item_count": 15,
|
||||
"created_at": "2026-03-31T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": 10,
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.1.2 获取BOM详情
|
||||
|
||||
```
|
||||
GET /api/v1/boms/{bom_id}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"product_id": 1,
|
||||
"code": "BOM-001",
|
||||
"name": "产品A物料清单",
|
||||
"version": "1.0",
|
||||
"type": "manufacturing",
|
||||
"status": "released",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"level": 1,
|
||||
"sequence": 1,
|
||||
"material_code": "M001",
|
||||
"material_name": "零件A",
|
||||
"quantity": 10,
|
||||
"unit": "pcs",
|
||||
"scrap_rate": 0.05
|
||||
}
|
||||
],
|
||||
"ai_analysis_status": "completed",
|
||||
"ai_recommendation": "建议使用替代物料M002可降低成本15%"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.1.3 创建BOM
|
||||
|
||||
```
|
||||
POST /api/v1/boms
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"product_id": 1,
|
||||
"code": "BOM-001",
|
||||
"name": "产品A物料清单",
|
||||
"type": "manufacturing",
|
||||
"items": [
|
||||
{
|
||||
"material_code": "M001",
|
||||
"quantity": 10,
|
||||
"unit": "pcs",
|
||||
"scrap_rate": 0.05
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.1.4 更新BOM
|
||||
|
||||
```
|
||||
PUT /api/v1/boms/{bom_id}
|
||||
```
|
||||
|
||||
#### 3.1.5 删除BOM
|
||||
|
||||
```
|
||||
DELETE /api/v1/boms/{bom_id}
|
||||
```
|
||||
|
||||
### 3.2 BOM操作接口
|
||||
|
||||
#### 3.2.1 BOM展开
|
||||
|
||||
```
|
||||
GET /api/v1/boms/{bom_id}/expand
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| level | int | 展开层级,-1为全部展开 |
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"bom_id": 1,
|
||||
"expand_type": "full",
|
||||
"items": [
|
||||
{
|
||||
"level": 1,
|
||||
"material_code": "M001",
|
||||
"material_name": "部件A",
|
||||
"quantity": 1,
|
||||
"children": [
|
||||
{
|
||||
"level": 2,
|
||||
"material_code": "M101",
|
||||
"material_name": "零件A1",
|
||||
"quantity": 5,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total_items": 15,
|
||||
"total_levels": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.2 BOM对比
|
||||
|
||||
```
|
||||
POST /api/v1/boms/compare
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"bom_id_1": 1,
|
||||
"bom_id_2": 2
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"added": [
|
||||
{
|
||||
"material_code": "M005",
|
||||
"material_name": "新增零件",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"removed": [
|
||||
{
|
||||
"material_code": "M003",
|
||||
"material_name": "删除零件",
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"modified": [
|
||||
{
|
||||
"material_code": "M001",
|
||||
"old_quantity": 10,
|
||||
"new_quantity": 15,
|
||||
"change_percent": 50
|
||||
}
|
||||
],
|
||||
"unchanged": 12
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.3 BOM复制
|
||||
|
||||
```
|
||||
POST /api/v1/boms/{bom_id}/copy
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"new_code": "BOM-001-COPY",
|
||||
"new_name": "产品A物料清单副本"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 AI智能接口
|
||||
|
||||
#### 3.3.1 AI优化建议
|
||||
|
||||
```
|
||||
POST /api/v1/boms/{bom_id}/ai-optimize
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"optimizations": [
|
||||
{
|
||||
"type": "material_substitution",
|
||||
"priority": "high",
|
||||
"original_material": "M001",
|
||||
"suggested_material": "M002",
|
||||
"reason": "成本降低15%,性能相当",
|
||||
"confidence": 0.88,
|
||||
"estimated_savings": 1500.00
|
||||
},
|
||||
{
|
||||
"type": "quantity_optimization",
|
||||
"material_code": "M003",
|
||||
"current_quantity": 10,
|
||||
"suggested_quantity": 8,
|
||||
"reason": "根据历史数据分析,可减少20%用量",
|
||||
"confidence": 0.82
|
||||
}
|
||||
],
|
||||
"similar_boms": [
|
||||
{
|
||||
"id": 5,
|
||||
"product_name": "相似产品B",
|
||||
"similarity": 0.85,
|
||||
"common_items": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3.2 相似BOM检测
|
||||
|
||||
```
|
||||
POST /api/v1/boms/{bom_id}/similarity
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"similar_boms": [
|
||||
{
|
||||
"id": 3,
|
||||
"product_name": "产品B",
|
||||
"similarity_score": 0.92,
|
||||
"matching_items": 15,
|
||||
"total_items": 18
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、C++引擎层
|
||||
|
||||
### 4.1 BOM计算引擎
|
||||
|
||||
**服务名:** `plm-engine-bom`
|
||||
|
||||
**核心功能:**
|
||||
- 高性能BOM层级展开
|
||||
- BOM差异计算
|
||||
- BOM成本估算(ONNX模型推理)
|
||||
|
||||
**pybind11绑定示例:**
|
||||
|
||||
```cpp
|
||||
// bom_engine.cpp
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
struct BOMItem {
|
||||
int id;
|
||||
int parent_id;
|
||||
std::string material_code;
|
||||
double quantity;
|
||||
int level;
|
||||
};
|
||||
|
||||
class BOMEngine {
|
||||
public:
|
||||
// BOM展开
|
||||
std::vector<BOMItem> expandBOM(
|
||||
const std::vector<BOMItem>& items,
|
||||
int max_level = -1
|
||||
) {
|
||||
// 实现BOM展开逻辑
|
||||
}
|
||||
|
||||
// BOM差异计算
|
||||
std::unordered_map<std::string, std::vector<BOMItem>> compareBOMs(
|
||||
const std::vector<BOMItem>& bom1,
|
||||
const std::vector<BOMItem>& bom2
|
||||
) {
|
||||
// 实现BOM对比逻辑
|
||||
}
|
||||
|
||||
// BOM成本估算(ONNX推理)
|
||||
double estimateCost(
|
||||
const std::vector<BOMItem>& items,
|
||||
const std::string& model_path
|
||||
) {
|
||||
// ONNX模型推理
|
||||
}
|
||||
};
|
||||
|
||||
PYBIND11_MODULE(bom_engine, m) {
|
||||
py::class_<BOMItem>(m, "BOMItem")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("id", &BOMItem::id)
|
||||
.def_readwrite("parent_id", &BOMItem::parent_id)
|
||||
.def_readwrite("material_code", &BOMItem::material_code)
|
||||
.def_readwrite("quantity", &BOMItem::quantity)
|
||||
.def_readwrite("level", &BOMItem::level);
|
||||
|
||||
py::class_<BOMEngine>(m, "BOMEngine")
|
||||
.def(py::init<>())
|
||||
.def("expand_bom", &BOMEngine::expandBOM)
|
||||
.def("compare_boms", &BOMEngine::compareBOMs)
|
||||
.def("estimate_cost", &BOMEngine::estimateCost);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Python调用示例
|
||||
|
||||
```python
|
||||
# services/bom_engine.py
|
||||
from bom_engine import BOMEngine, BOMItem
|
||||
|
||||
class BOMEngineService:
|
||||
def __init__(self):
|
||||
self.engine = BOMEngine()
|
||||
|
||||
def expand_bom(self, items: list, max_level: int = -1) -> list:
|
||||
"""展开BOM"""
|
||||
bom_items = [
|
||||
BOMItem(
|
||||
id=item['id'],
|
||||
parent_id=item['parent_id'],
|
||||
material_code=item['material_code'],
|
||||
quantity=item['quantity'],
|
||||
level=item['level']
|
||||
)
|
||||
for item in items
|
||||
]
|
||||
result = self.engine.expand_bom(bom_items, max_level)
|
||||
return [
|
||||
{
|
||||
'id': item.id,
|
||||
'parent_id': item.parent_id,
|
||||
'material_code': item.material_code,
|
||||
'quantity': item.quantity,
|
||||
'level': item.level
|
||||
}
|
||||
for item in result
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、AI模块
|
||||
|
||||
### 5.1 BOM优化器
|
||||
|
||||
```python
|
||||
# ai/bom_optimizer.py
|
||||
from openai import OpenAI
|
||||
from app.core.config import settings
|
||||
|
||||
class BOMOptimizer:
|
||||
def __init__(self):
|
||||
self.client = OpenAI(api_key=settings.AI_API_KEY)
|
||||
|
||||
async def optimize_bom(self, bom_data: dict) -> dict:
|
||||
"""AI优化BOM"""
|
||||
prompt = f"""
|
||||
分析以下BOM数据,提供优化建议:
|
||||
|
||||
BOM名称:{bom_data['name']}
|
||||
物料清单:
|
||||
{self._format_items(bom_data['items'])}
|
||||
|
||||
请从以下角度分析:
|
||||
1. 物料替代建议(成本更低/性能更好)
|
||||
2. 数量优化建议
|
||||
3. 层级结构优化建议
|
||||
"""
|
||||
|
||||
response = await self.client.chat.completions.create(
|
||||
model=settings.AI_MODEL,
|
||||
messages=[
|
||||
{"role": "system", "content": "你是PLM系统的BOM优化专家"},
|
||||
{"role": "user", "content": prompt}
|
||||
]
|
||||
)
|
||||
|
||||
return self._parse_optimization(response.choices[0].message.content)
|
||||
|
||||
def _format_items(self, items: list) -> str:
|
||||
return "\n".join([
|
||||
f"- {item['material_code']}: {item['material_name']} x {item['quantity']} {item['unit']}"
|
||||
for item in items
|
||||
])
|
||||
```
|
||||
|
||||
### 5.2 相似度检测
|
||||
|
||||
```python
|
||||
# ai/similarity.py
|
||||
from pgvector.sqlalchemy import Vector
|
||||
from sqlalchemy import text
|
||||
from app.core.database import engine
|
||||
|
||||
class BOMSimilarityService:
|
||||
def __init__(self):
|
||||
self.dimension = 1536 # OpenAI embedding维度
|
||||
|
||||
async def find_similar_boms(
|
||||
self,
|
||||
bom_id: int,
|
||||
threshold: float = 0.8,
|
||||
limit: int = 5
|
||||
) -> list:
|
||||
"""查找相似BOM"""
|
||||
query = text("""
|
||||
SELECT
|
||||
b.id,
|
||||
b.name,
|
||||
b.code,
|
||||
1 - (b.embedding_vector <=> (
|
||||
SELECT embedding_vector FROM boms WHERE id = :bom_id
|
||||
)) as similarity
|
||||
FROM boms b
|
||||
WHERE b.id != :bom_id
|
||||
AND b.status = 'released'
|
||||
AND 1 - (b.embedding_vector <=> (
|
||||
SELECT embedding_vector FROM boms WHERE id = :bom_id
|
||||
)) >= :threshold
|
||||
ORDER BY similarity DESC
|
||||
LIMIT :limit
|
||||
""")
|
||||
|
||||
async with engine.begin() as conn:
|
||||
result = await conn.execute(
|
||||
query,
|
||||
{"bom_id": bom_id, "threshold": threshold, "limit": limit}
|
||||
)
|
||||
return result.fetchall()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、业务流程
|
||||
|
||||
### 6.1 BOM创建流程
|
||||
|
||||
```
|
||||
1. 创建BOM主记录
|
||||
↓
|
||||
2. 添加BOM明细项
|
||||
↓
|
||||
3. 校验物料有效性
|
||||
↓
|
||||
4. 计算层级结构
|
||||
↓
|
||||
5. 生成向量嵌入
|
||||
↓
|
||||
6. AI分析(异步)
|
||||
↓
|
||||
7. 返回创建结果
|
||||
```
|
||||
|
||||
### 6.2 BOM审批流程
|
||||
|
||||
```
|
||||
草稿 → 提交审批 → 审批中 → 已批准/已拒绝
|
||||
↓
|
||||
发布
|
||||
```
|
||||
|
||||
### 6.3 BOM版本管理
|
||||
|
||||
```
|
||||
1. 创建新版本
|
||||
↓
|
||||
2. 复制当前BOM
|
||||
↓
|
||||
3. 修改内容
|
||||
↓
|
||||
4. 生成版本差异
|
||||
↓
|
||||
5. AI影响分析
|
||||
↓
|
||||
6. 提交审批
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、性能指标
|
||||
|
||||
### 7.1 响应时间要求
|
||||
|
||||
| 操作 | 响应时间 | 说明 |
|
||||
|------|----------|------|
|
||||
| 获取BOM列表 | < 200ms | 含分页 |
|
||||
| 获取BOM详情 | < 300ms | 含明细 |
|
||||
| 创建BOM | < 500ms | 含校验 |
|
||||
| BOM展开 | < 1s | 5层以内 |
|
||||
| BOM对比 | < 2s | 100项以内 |
|
||||
| AI优化 | < 5s | 含推理 |
|
||||
|
||||
### 7.2 缓存策略
|
||||
|
||||
| 数据 | 缓存时间 | 缓存键 |
|
||||
|------|----------|--------|
|
||||
| BOM详情 | 5分钟 | bom:{id} |
|
||||
| BOM展开结果 | 10分钟 | bom:{id}:expand:{level} |
|
||||
| AI优化结果 | 1小时 | bom:{id}:optimize |
|
||||
|
||||
---
|
||||
|
||||
## 八、错误处理
|
||||
|
||||
### 8.1 错误码定义
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 50001 | BOM不存在 |
|
||||
| 50002 | BOM版本冲突 |
|
||||
| 50003 | 物料不存在 |
|
||||
| 50004 | 层级超限 |
|
||||
| 50005 | AI分析失败 |
|
||||
|
||||
### 8.2 异常处理示例
|
||||
|
||||
```python
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
class BOMNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class BOMVersionConflictError(Exception):
|
||||
pass
|
||||
|
||||
@router.get("/boms/{bom_id}")
|
||||
async def get_bom(bom_id: int):
|
||||
try:
|
||||
bom = await bom_service.get_bom(bom_id)
|
||||
if not bom:
|
||||
raise BOMNotFoundError(f"BOM {bom_id} not found")
|
||||
return bom
|
||||
except BOMNotFoundError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=str(e)
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、部署配置
|
||||
|
||||
### 9.1 Docker配置
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
plm-bom-service:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8003:8000"
|
||||
- "50053:50051"
|
||||
environment:
|
||||
DATABASE_URL: postgresql://plm:plm123@postgres:5432/plm_db
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
AI_API_KEY: ${AI_API_KEY}
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
```
|
||||
|
||||
### 9.2 环境变量
|
||||
|
||||
```bash
|
||||
# BOM服务配置
|
||||
BOM_SERVICE_PORT=8003
|
||||
BOM_GRPC_PORT=50053
|
||||
BOM_MAX_LEVELS=10
|
||||
BOM_MAX_ITEMS=1000
|
||||
|
||||
# AI配置
|
||||
AI_OPTIMIZATION_ENABLED=true
|
||||
AI_SIMILARITY_THRESHOLD=0.8
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、附录
|
||||
|
||||
### 10.1 BOM类型枚举
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| design | 设计BOM |
|
||||
| manufacturing | 制造BOM |
|
||||
| service | 服务BOM |
|
||||
| sales | 销售BOM |
|
||||
|
||||
### 10.2 BOM状态枚举
|
||||
|
||||
| 状态 | 说明 |
|
||||
|------|------|
|
||||
| draft | 草稿 |
|
||||
| submitted | 已提交 |
|
||||
| approved | 已批准 |
|
||||
| rejected | 已拒绝 |
|
||||
| released | 已发布 |
|
||||
| frozen | 已冻结 |
|
||||
| obsolete | 已废弃 |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 20:35_
|
||||
_维护人:笔杆子 (creator)_
|
||||
246
architecture/PLM技术文档摘要.md
Normal file
246
architecture/PLM技术文档摘要.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# PLM 系统技术文档摘要
|
||||
|
||||
> **版本**:V1.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子 (creator)
|
||||
> **状态**:已发布
|
||||
|
||||
---
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 项目名称
|
||||
PLM System - 产品生命周期管理系统
|
||||
|
||||
### 1.2 项目周期
|
||||
- **总周期**:48周
|
||||
- **当前进度**:M0完成100%,M1进行中5%
|
||||
|
||||
### 1.3 项目规模
|
||||
- **任务总数**:198项
|
||||
- **里程碑数**:7个(M0-M6)
|
||||
|
||||
---
|
||||
|
||||
## 二、团队组织
|
||||
|
||||
### 2.1 团队规模
|
||||
- **总人数**:14人
|
||||
- **工作模式**:7×24自主运行(心跳30分钟)
|
||||
|
||||
### 2.2 架构分层
|
||||
|
||||
| 层级 | 角色 | 人数 | 汇报对象 |
|
||||
|------|------|------|----------|
|
||||
| 私人助理 | 小哈 | 1人 | 老大 |
|
||||
| C-Level高管 | CEO/COO/CTO/CMO/参谋 | 5人 | 老大 |
|
||||
| 研发体系 | 研发总监+前端+后端+测试+产品 | 5人 | CTO |
|
||||
| 支撑体系 | 文档总监+运维总监+知识工程师 | 3人 | COO/CTO |
|
||||
|
||||
---
|
||||
|
||||
## 三、技术架构
|
||||
|
||||
### 3.1 统一技术栈
|
||||
|
||||
| 层级 | 技术 | 版本 |
|
||||
|------|------|------|
|
||||
| 后端语言 | Python | 3.11 |
|
||||
| Web框架 | FastAPI | 0.100+ |
|
||||
| ORM | SQLAlchemy | 2.0 |
|
||||
| 数据验证 | Pydantic | 2.0 |
|
||||
| 微服务通信 | gRPC + Protobuf | - |
|
||||
| 数据库 | PostgreSQL + pgvector | 16 |
|
||||
| 缓存 | Redis | 7 |
|
||||
| 消息队列 | RabbitMQ | 3.12 |
|
||||
| 对象存储 | MinIO | - |
|
||||
| 搜索引擎 | OpenSearch | - |
|
||||
| 前端框架 | Vue 3 + TypeScript | 3.4+ |
|
||||
| UI组件 | Element Plus | 2.5 |
|
||||
| 状态管理 | Pinia | 2.1 |
|
||||
| C++引擎 | C++17/20 + pybind11 | - |
|
||||
|
||||
### 3.2 架构特点(10大特点)
|
||||
|
||||
1. **前后端分离** - Vue 3 + FastAPI
|
||||
2. **C++引擎层** - 高性能计算核心
|
||||
3. **gRPC通信** - 高效服务间通信
|
||||
4. **pybind11绑定** - C++/Python无缝集成
|
||||
5. **AI原生架构** - 每个服务都有AI集成点
|
||||
6. **向量搜索** - pgvector语义搜索
|
||||
7. **异步处理** - FastAPI async + RabbitMQ
|
||||
8. **类型安全** - TypeScript + Pydantic
|
||||
9. **容器化部署** - Docker + Kubernetes
|
||||
10. **微服务架构** - 业务导向服务拆分
|
||||
|
||||
### 3.3 微服务清单(11个)
|
||||
|
||||
| 服务名 | 职责 | AI能力 |
|
||||
|--------|------|--------|
|
||||
| plm-auth-service | 系统管理 | 智能权限推荐 |
|
||||
| plm-product-service | 产品管理 | AI分类/智能推荐 |
|
||||
| plm-bom-service | BOM管理 | AI优化建议/相似检测 |
|
||||
| plm-route-service | 工艺管理 | AI工艺推荐 |
|
||||
| plm-document-service | 文档管理 | AI智能标签/内容摘要 |
|
||||
| plm-change-service | 变更管理 | AI风险预测/影响分析 |
|
||||
| plm-notification-service | 通知管理 | AI智能推送策略 |
|
||||
| plm-report-service | 报表管理 | AI报表生成/智能分析 |
|
||||
| plm-workflow-service | 工作流管理 | AI流程推荐/智能审批 |
|
||||
| plm-search-service | 搜索服务 | 向量搜索+NLP查询 |
|
||||
| plm-ai-service | AI核心服务 | 模型管理/向量嵌入 |
|
||||
|
||||
---
|
||||
|
||||
## 四、AI原生能力
|
||||
|
||||
### 4.1 AI能力清单(12项)
|
||||
|
||||
| # | 能力 | 说明 |
|
||||
|---|------|------|
|
||||
| 1 | 智能BOM推荐 | AI分析相似产品 |
|
||||
| 2 | 自然语言查询 | NL2SQL转换 |
|
||||
| 3 | 智能文档生成 | AI辅助编写 |
|
||||
| 4 | 变更风险预测 | AI分析影响范围 |
|
||||
| 5 | 智能分类标签 | AI自动分类 |
|
||||
| 6 | 智能数据校验 | AI检测异常 |
|
||||
| 7 | 向量搜索引擎 | pgvector语义搜索 |
|
||||
| 8 | AI搜索助手 | 智能补全/建议 |
|
||||
| 9 | 多模态搜索 | 图片/CAD/文档搜索 |
|
||||
| 10 | AI性能监控 | 推理延迟/Token统计 |
|
||||
| 11 | 模型版本管理 | A/B测试/灰度发布 |
|
||||
| 12 | 代码生成助手 | AI辅助开发 |
|
||||
|
||||
### 4.2 AI架构原则
|
||||
|
||||
1. 每个服务都有AI集成点
|
||||
2. 数据模型支持AI分析字段
|
||||
3. API支持AI调用方式(流式/批量/异步)
|
||||
4. 前端支持AI交互组件
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库设计
|
||||
|
||||
### 5.1 数据库选型
|
||||
|
||||
| 组件 | 技术 | 说明 |
|
||||
|------|------|------|
|
||||
| 主数据库 | PostgreSQL 16 | 企业级关系数据库 |
|
||||
| 向量扩展 | pgvector | AI向量搜索 |
|
||||
| 缓存 | Redis 7 | 高性能缓存 |
|
||||
|
||||
### 5.2 AI相关表结构
|
||||
|
||||
| 表名 | 说明 |
|
||||
|------|------|
|
||||
| embeddings | 向量嵌入表 |
|
||||
| ai_analysis_results | AI分析结果表 |
|
||||
| ai_models | AI模型配置表 |
|
||||
| ai_prompts | Prompt模板表 |
|
||||
| ai_call_logs | AI调用日志表 |
|
||||
| ai_recommendation_cache | 推荐缓存表 |
|
||||
|
||||
### 5.3 业务表AI字段
|
||||
|
||||
每个业务表新增:
|
||||
- `ai_analysis_status` - AI分析状态
|
||||
- `ai_recommendation` - AI推荐内容
|
||||
- `embedding_vector` - 向量嵌入
|
||||
- `ai_confidence_score` - AI置信度
|
||||
|
||||
---
|
||||
|
||||
## 六、里程碑规划
|
||||
|
||||
| 里程碑 | 周期 | 任务数 | 重点内容 |
|
||||
|--------|------|--------|----------|
|
||||
| M0 | 1-6周 | 11项 | 项目启动、基础设施 |
|
||||
| M1 | 7-18周 | 60项 | 核心PLM功能模块 |
|
||||
| M2 | 19-28周 | 34项 | 服务集成与扩展 |
|
||||
| M3 | 29-36周 | 27项 | AI集成、高级功能 |
|
||||
| M4 | 37-40周 | 15项 | 性能优化、安全加固 |
|
||||
| M5 | 41-44周 | 13项 | 全面测试与QA |
|
||||
| M6 | 45-48周 | 16项 | 生产部署与上线 |
|
||||
|
||||
---
|
||||
|
||||
## 七、仓库命名规范
|
||||
|
||||
### 7.1 当前仓库数量
|
||||
**19个仓库**
|
||||
|
||||
### 7.2 命名架构
|
||||
|
||||
| 层级 | 命名格式 | 示例 |
|
||||
|------|----------|------|
|
||||
| C++引擎层 | plm-engine-* | plm-engine-bom |
|
||||
| Python微服务 | plm-*-service | plm-auth-service |
|
||||
| gRPC通信层 | plm-grpc-proto | plm-grpc-proto |
|
||||
| 前端应用 | plm-web-* | plm-web-frontend |
|
||||
| 基础设施 | plm-infra-* | plm-infra-k8s |
|
||||
| 开发工作区 | workspace-dev* | workspace-dev1 |
|
||||
|
||||
---
|
||||
|
||||
## 八、业务模块
|
||||
|
||||
### 8.1 核心模块(P0)
|
||||
|
||||
| 模块 | AI能力 |
|
||||
|------|--------|
|
||||
| 系统管理 | 智能权限推荐 |
|
||||
| 产品管理 | AI分类/语义搜索 |
|
||||
| BOM管理 | AI优化/相似检测 |
|
||||
|
||||
### 8.2 重要模块(P1)
|
||||
|
||||
| 模块 | AI能力 |
|
||||
|------|--------|
|
||||
| AI服务 | LLM/向量核心能力 |
|
||||
| 工艺管理 | AI工艺推荐 |
|
||||
| 文档管理 | AI标签/语义搜索 |
|
||||
| 变更管理 | AI风险预测 |
|
||||
|
||||
---
|
||||
|
||||
## 九、开发环境
|
||||
|
||||
### 9.1 服务端口
|
||||
|
||||
| 服务 | 端口 |
|
||||
|------|------|
|
||||
| PostgreSQL | 5432 |
|
||||
| Redis | 6379 |
|
||||
| Nacos | 8848 |
|
||||
| RabbitMQ | 5672 |
|
||||
| MinIO | 9000 |
|
||||
| OpenSearch | 9200 |
|
||||
| 后端服务HTTP | 8001-8010 |
|
||||
| 后端服务gRPC | 50051-50060 |
|
||||
| 前端服务 | 5173 |
|
||||
|
||||
### 9.2 默认管理员
|
||||
|
||||
```
|
||||
用户名: admin
|
||||
密码: Admin@123456
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、相关链接
|
||||
|
||||
| 资源 | 链接 |
|
||||
|------|------|
|
||||
| 任务清单 | https://www.kdocs.cn/l/cnW2jdHWgNib |
|
||||
| 组织架构 | https://www.kdocs.cn/l/cd45R9zosieP |
|
||||
| 技术架构 | https://www.kdocs.cn/l/cvWwrJysIbiu |
|
||||
| 仓库规范 | https://www.kdocs.cn/l/ccHxw48bJQPH |
|
||||
| 业务模块 | https://www.kdocs.cn/l/cphkaiMTu4lo |
|
||||
| 数据库设计 | https://www.kdocs.cn/l/coHA4F8KEk2U |
|
||||
| 问题清单 | https://www.kdocs.cn/l/cdEAQy9VT7yo |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 20:10_
|
||||
_维护人:笔杆子 (creator)_
|
||||
973
development/M1-S4开发手册.md
Normal file
973
development/M1-S4开发手册.md
Normal file
@@ -0,0 +1,973 @@
|
||||
# M1-S4 开发手册 - 产品数据管理(进阶)
|
||||
|
||||
> **版本**:V1.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子 (creator)
|
||||
> **状态**:已发布
|
||||
> **里程碑**:M1 核心PLM功能模块
|
||||
> **阶段**:S4 产品数据管理-进阶
|
||||
> **周期**:第9-10周
|
||||
|
||||
---
|
||||
|
||||
## 一、阶段概述
|
||||
|
||||
### 1.1 阶段目标
|
||||
|
||||
完成产品数据管理进阶功能开发,包括BOM管理、属性模板、批量导入导出、数据校验等核心功能。
|
||||
|
||||
### 1.2 任务清单
|
||||
|
||||
| 任务编号 | 任务名称 | 负责人 | 预计工时 | 状态 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| M1-007 | BOM(物料清单)数据模型 | 后端工程师 | 2天 | 🔄 进行中 |
|
||||
| M1-008 | BOM管理API开发 | 后端工程师 | 3天 | ⏳ 待开始 |
|
||||
| M1-009 | BOM树形展示页面 | 前端工程师 | 2天 | ⏳ 待开始 |
|
||||
| M1-010 | 产品属性自定义模板 | 后端工程师 | 2天 | ⏳ 待开始 |
|
||||
| M1-011 | 批量导入导出功能 | 后端工程师 | 2天 | ⏳ 待开始 |
|
||||
| M1-012 | 数据校验规则引擎 | 后端工程师 | 3天 | ⏳ 待开始 |
|
||||
|
||||
**总计:14天(2周)**
|
||||
|
||||
---
|
||||
|
||||
## 二、M1-007:BOM数据模型
|
||||
|
||||
### 2.1 数据库设计
|
||||
|
||||
#### 2.1.1 BOM主表 DDL
|
||||
|
||||
```sql
|
||||
-- BOM主表
|
||||
CREATE TABLE boms (
|
||||
id SERIAL PRIMARY KEY,
|
||||
product_id INTEGER NOT NULL REFERENCES products(id),
|
||||
code VARCHAR(50) UNIQUE NOT NULL,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
version VARCHAR(20) NOT NULL DEFAULT '1.0',
|
||||
type VARCHAR(20) NOT NULL DEFAULT 'manufacturing',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||||
parent_bom_id INTEGER REFERENCES boms(id),
|
||||
effective_date DATE,
|
||||
expiry_date DATE,
|
||||
|
||||
-- AI字段
|
||||
ai_analysis_status VARCHAR(20) DEFAULT 'pending',
|
||||
ai_recommendation TEXT,
|
||||
ai_confidence_score FLOAT,
|
||||
embedding_vector VECTOR(1536),
|
||||
|
||||
-- 审计字段
|
||||
created_by INTEGER REFERENCES users(id),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT uk_bom_product_version UNIQUE (product_id, version)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_boms_product_id ON boms(product_id);
|
||||
CREATE INDEX idx_boms_status ON boms(status);
|
||||
CREATE INDEX idx_boms_code ON boms(code);
|
||||
```
|
||||
|
||||
#### 2.1.2 BOM明细表 DDL
|
||||
|
||||
```sql
|
||||
-- BOM明细表
|
||||
CREATE TABLE bom_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
bom_id INTEGER NOT NULL REFERENCES boms(id) ON DELETE CASCADE,
|
||||
parent_item_id INTEGER REFERENCES bom_items(id),
|
||||
level INTEGER NOT NULL DEFAULT 1,
|
||||
sequence INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- 物料信息
|
||||
material_id INTEGER REFERENCES materials(id),
|
||||
material_code VARCHAR(50) NOT NULL,
|
||||
material_name VARCHAR(200) NOT NULL,
|
||||
|
||||
-- 数量信息
|
||||
quantity DECIMAL(10,4) NOT NULL,
|
||||
unit VARCHAR(20) NOT NULL,
|
||||
scrap_rate DECIMAL(5,2) DEFAULT 0,
|
||||
|
||||
-- 替代物料
|
||||
substitute_material_id INTEGER REFERENCES materials(id),
|
||||
|
||||
-- 有效期
|
||||
effective_date DATE,
|
||||
expiry_date DATE,
|
||||
|
||||
-- 其他
|
||||
remark TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_bom_items_bom_id ON bom_items(bom_id);
|
||||
CREATE INDEX idx_bom_items_material_code ON bom_items(material_code);
|
||||
CREATE INDEX idx_bom_items_parent_id ON bom_items(parent_item_id);
|
||||
```
|
||||
|
||||
#### 2.1.3 BOM版本差异表 DDL
|
||||
|
||||
```sql
|
||||
-- BOM版本差异表
|
||||
CREATE TABLE bom_version_diffs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
bom_id INTEGER NOT NULL REFERENCES boms(id),
|
||||
old_version VARCHAR(20) NOT NULL,
|
||||
new_version VARCHAR(20) NOT NULL,
|
||||
diff_type VARCHAR(20) NOT NULL,
|
||||
diff_details JSONB NOT NULL,
|
||||
ai_impact_analysis TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 2.2 ORM模型
|
||||
|
||||
```python
|
||||
# models/bom.py
|
||||
from sqlalchemy import Column, Integer, String, Numeric, Date, Text, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from pgvector.sqlalchemy import Vector
|
||||
from app.core.database import Base
|
||||
|
||||
class BOM(Base):
|
||||
__tablename__ = "boms"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
product_id = Column(Integer, ForeignKey("products.id"), nullable=False)
|
||||
code = Column(String(50), unique=True, nullable=False)
|
||||
name = Column(String(200), nullable=False)
|
||||
version = Column(String(20), nullable=False, default="1.0")
|
||||
type = Column(String(20), nullable=False, default="manufacturing")
|
||||
status = Column(String(20), nullable=False, default="draft")
|
||||
parent_bom_id = Column(Integer, ForeignKey("boms.id"))
|
||||
effective_date = Column(Date)
|
||||
expiry_date = Column(Date)
|
||||
|
||||
# AI字段
|
||||
ai_analysis_status = Column(String(20), default="pending")
|
||||
ai_recommendation = Column(Text)
|
||||
ai_confidence_score = Column(Numeric(5, 4))
|
||||
embedding_vector = Column(Vector(1536))
|
||||
|
||||
# 审计字段
|
||||
created_by = Column(Integer, ForeignKey("users.id"))
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
# 关系
|
||||
product = relationship("Product", back_populates="boms")
|
||||
items = relationship("BOMItem", back_populates="bom", cascade="all, delete-orphan")
|
||||
parent_bom = relationship("BOM", remote_side=[id], backref="child_boms")
|
||||
|
||||
|
||||
class BOMItem(Base):
|
||||
__tablename__ = "bom_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
bom_id = Column(Integer, ForeignKey("boms.id"), nullable=False)
|
||||
parent_item_id = Column(Integer, ForeignKey("bom_items.id"))
|
||||
level = Column(Integer, nullable=False, default=1)
|
||||
sequence = Column(Integer, nullable=False, default=0)
|
||||
|
||||
material_id = Column(Integer, ForeignKey("materials.id"))
|
||||
material_code = Column(String(50), nullable=False)
|
||||
material_name = Column(String(200), nullable=False)
|
||||
|
||||
quantity = Column(Numeric(10, 4), nullable=False)
|
||||
unit = Column(String(20), nullable=False)
|
||||
scrap_rate = Column(Numeric(5, 2), default=0)
|
||||
|
||||
substitute_material_id = Column(Integer, ForeignKey("materials.id"))
|
||||
|
||||
effective_date = Column(Date)
|
||||
expiry_date = Column(Date)
|
||||
remark = Column(Text)
|
||||
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
# 关系
|
||||
bom = relationship("BOM", back_populates="items")
|
||||
children = relationship("BOMItem", backref="parent_item", remote_side=[id])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、M1-008:BOM管理API开发
|
||||
|
||||
### 3.1 API路由设计
|
||||
|
||||
```python
|
||||
# api/bom_router.py
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from typing import List, Optional
|
||||
from app.schemas.bom_schemas import (
|
||||
BOMCreate, BOMUpdate, BOMResponse, BOMDetailResponse,
|
||||
BOMExpandResponse, BOMCompareRequest, BOMCompareResponse
|
||||
)
|
||||
from app.services.bom_service import BOMService
|
||||
|
||||
router = APIRouter(prefix="/boms", tags=["BOMs"])
|
||||
|
||||
@router.get("/", response_model=List[BOMResponse])
|
||||
async def list_boms(
|
||||
product_id: Optional[int] = None,
|
||||
status: Optional[str] = None,
|
||||
type: Optional[str] = None,
|
||||
keyword: Optional[str] = None,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""获取BOM列表"""
|
||||
return await service.get_boms(
|
||||
product_id=product_id,
|
||||
status=status,
|
||||
type=type,
|
||||
keyword=keyword,
|
||||
page=page,
|
||||
page_size=page_size
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{bom_id}", response_model=BOMDetailResponse)
|
||||
async def get_bom(
|
||||
bom_id: int,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""获取BOM详情"""
|
||||
bom = await service.get_bom(bom_id)
|
||||
if not bom:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"BOM {bom_id} not found"
|
||||
)
|
||||
return bom
|
||||
|
||||
|
||||
@router.post("/", response_model=BOMResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_bom(
|
||||
bom: BOMCreate,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""创建BOM"""
|
||||
return await service.create_bom(bom)
|
||||
|
||||
|
||||
@router.put("/{bom_id}", response_model=BOMResponse)
|
||||
async def update_bom(
|
||||
bom_id: int,
|
||||
bom: BOMUpdate,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""更新BOM"""
|
||||
return await service.update_bom(bom_id, bom)
|
||||
|
||||
|
||||
@router.delete("/{bom_id}")
|
||||
async def delete_bom(
|
||||
bom_id: int,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""删除BOM"""
|
||||
await service.delete_bom(bom_id)
|
||||
return {"message": "删除成功"}
|
||||
|
||||
|
||||
@router.get("/{bom_id}/expand", response_model=BOMExpandResponse)
|
||||
async def expand_bom(
|
||||
bom_id: int,
|
||||
level: int = -1,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""展开BOM"""
|
||||
return await service.expand_bom(bom_id, level)
|
||||
|
||||
|
||||
@router.post("/compare", response_model=BOMCompareResponse)
|
||||
async def compare_boms(
|
||||
request: BOMCompareRequest,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""对比BOM"""
|
||||
return await service.compare_boms(request.bom_id_1, request.bom_id_2)
|
||||
|
||||
|
||||
@router.post("/{bom_id}/copy", response_model=BOMResponse)
|
||||
async def copy_bom(
|
||||
bom_id: int,
|
||||
new_code: str,
|
||||
new_name: str,
|
||||
service: BOMService = Depends()
|
||||
):
|
||||
"""复制BOM"""
|
||||
return await service.copy_bom(bom_id, new_code, new_name)
|
||||
```
|
||||
|
||||
### 3.2 业务逻辑实现
|
||||
|
||||
```python
|
||||
# services/bom_service.py
|
||||
from typing import List, Optional, Dict
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, func
|
||||
from app.models.bom import BOM, BOMItem
|
||||
from app.schemas.bom_schemas import BOMCreate, BOMUpdate
|
||||
from app.services.bom_engine import BOMEngineService
|
||||
from app.ai.bom_optimizer import BOMOptimizer
|
||||
|
||||
class BOMService:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
self.engine = BOMEngineService()
|
||||
self.optimizer = BOMOptimizer()
|
||||
|
||||
async def create_bom(self, bom_data: BOMCreate) -> BOM:
|
||||
"""创建BOM"""
|
||||
# 1. 创建BOM主记录
|
||||
bom = BOM(
|
||||
product_id=bom_data.product_id,
|
||||
code=bom_data.code,
|
||||
name=bom_data.name,
|
||||
type=bom_data.type
|
||||
)
|
||||
self.db.add(bom)
|
||||
await self.db.flush()
|
||||
|
||||
# 2. 添加BOM明细
|
||||
for item_data in bom_data.items:
|
||||
item = BOMItem(
|
||||
bom_id=bom.id,
|
||||
material_code=item_data.material_code,
|
||||
material_name=item_data.material_name,
|
||||
quantity=item_data.quantity,
|
||||
unit=item_data.unit,
|
||||
level=item_data.level or 1
|
||||
)
|
||||
self.db.add(item)
|
||||
|
||||
await self.db.commit()
|
||||
|
||||
# 3. 触发AI分析(异步)
|
||||
await self._trigger_ai_analysis(bom.id)
|
||||
|
||||
return bom
|
||||
|
||||
async def expand_bom(self, bom_id: int, max_level: int = -1) -> Dict:
|
||||
"""展开BOM"""
|
||||
# 获取所有明细项
|
||||
result = await self.db.execute(
|
||||
select(BOMItem).where(BOMItem.bom_id == bom_id)
|
||||
)
|
||||
items = result.scalars().all()
|
||||
|
||||
# 调用C++引擎展开
|
||||
expanded_items = self.engine.expand_bom(items, max_level)
|
||||
|
||||
return {
|
||||
"bom_id": bom_id,
|
||||
"expand_type": "full" if max_level == -1 else f"level_{max_level}",
|
||||
"items": expanded_items
|
||||
}
|
||||
|
||||
async def compare_boms(self, bom_id_1: int, bom_id_2: int) -> Dict:
|
||||
"""对比BOM"""
|
||||
# 获取两个BOM的明细
|
||||
result1 = await self.db.execute(
|
||||
select(BOMItem).where(BOMItem.bom_id == bom_id_1)
|
||||
)
|
||||
items1 = result1.scalars().all()
|
||||
|
||||
result2 = await self.db.execute(
|
||||
select(BOMItem).where(BOMItem.bom_id == bom_id_2)
|
||||
)
|
||||
items2 = result2.scalars().all()
|
||||
|
||||
# 调用C++引擎对比
|
||||
diff = self.engine.compare_boms(items1, items2)
|
||||
|
||||
return diff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、M1-009:BOM树形展示页面
|
||||
|
||||
### 4.1 组件设计
|
||||
|
||||
```vue
|
||||
<!-- views/BOM/BOMTree.vue -->
|
||||
<template>
|
||||
<div class="bom-tree-container">
|
||||
<div class="bom-tree-header">
|
||||
<h3>{{ bomInfo.name }} - 物料清单</h3>
|
||||
<div class="bom-tree-actions">
|
||||
<el-button @click="expandAll">全部展开</el-button>
|
||||
<el-button @click="collapseAll">全部折叠</el-button>
|
||||
<el-button type="primary" @click="exportBOM">导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
:data="treeData"
|
||||
:props="treeProps"
|
||||
node-key="id"
|
||||
:expand-on-click-node="false"
|
||||
:default-expand-all="false"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<div class="bom-item">
|
||||
<span class="item-code">{{ data.material_code }}</span>
|
||||
<span class="item-name">{{ data.material_name }}</span>
|
||||
<span class="item-quantity">
|
||||
{{ data.quantity }} {{ data.unit }}
|
||||
</span>
|
||||
<span class="item-level">L{{ data.level }}</span>
|
||||
<div class="item-actions">
|
||||
<el-button size="small" @click="editItem(data)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="deleteItem(data)">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getBOMDetail, expandBOM } from '@/api/boms'
|
||||
|
||||
interface BOMItem {
|
||||
id: number
|
||||
material_code: string
|
||||
material_name: string
|
||||
quantity: number
|
||||
unit: string
|
||||
level: number
|
||||
children?: BOMItem[]
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const treeRef = ref()
|
||||
const bomInfo = ref<any>({})
|
||||
const treeData = ref<BOMItem[]>([])
|
||||
|
||||
const treeProps = {
|
||||
children: 'children',
|
||||
label: 'material_name'
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const bomId = route.params.id as string
|
||||
await loadBOMTree(Number(bomId))
|
||||
})
|
||||
|
||||
async function loadBOMTree(bomId: number) {
|
||||
// 获取BOM详情
|
||||
const detail = await getBOMDetail(bomId)
|
||||
bomInfo.value = detail.data
|
||||
|
||||
// 获取展开数据
|
||||
const expand = await expandBOM(bomId, -1)
|
||||
treeData.value = buildTree(expand.data.items)
|
||||
}
|
||||
|
||||
function buildTree(items: any[]): BOMItem[] {
|
||||
const map = new Map()
|
||||
const roots: BOMItem[] = []
|
||||
|
||||
// 构建映射
|
||||
items.forEach(item => {
|
||||
map.set(item.id, { ...item, children: [] })
|
||||
})
|
||||
|
||||
// 构建树
|
||||
items.forEach(item => {
|
||||
const node = map.get(item.id)
|
||||
if (item.parent_item_id) {
|
||||
const parent = map.get(item.parent_item_id)
|
||||
if (parent) {
|
||||
parent.children.push(node)
|
||||
}
|
||||
} else {
|
||||
roots.push(node)
|
||||
}
|
||||
})
|
||||
|
||||
return roots
|
||||
}
|
||||
|
||||
function expandAll() {
|
||||
const nodes = treeRef.value?.store?.nodesMap
|
||||
for (const key in nodes) {
|
||||
nodes[key].expanded = true
|
||||
}
|
||||
}
|
||||
|
||||
function collapseAll() {
|
||||
const nodes = treeRef.value?.store?.nodesMap
|
||||
for (const key in nodes) {
|
||||
nodes[key].expanded = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bom-tree-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.bom-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.item-code {
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.item-quantity {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.item-level {
|
||||
background: #f4f4f5;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、M1-010:产品属性自定义模板
|
||||
|
||||
### 5.1 数据模型
|
||||
|
||||
```sql
|
||||
-- 属性模板表
|
||||
CREATE TABLE attribute_templates (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
category_id INTEGER REFERENCES product_categories(id),
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 属性定义表
|
||||
CREATE TABLE attribute_definitions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
template_id INTEGER REFERENCES attribute_templates(id) ON DELETE CASCADE,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
label VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(20) NOT NULL, -- string, number, select, date, etc.
|
||||
required BOOLEAN DEFAULT false,
|
||||
default_value TEXT,
|
||||
validation_rule TEXT,
|
||||
options JSONB, -- 用于select类型的选项
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 5.2 模板服务
|
||||
|
||||
```python
|
||||
# services/attribute_template_service.py
|
||||
from typing import List, Dict
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from app.models.attribute_template import AttributeTemplate, AttributeDefinition
|
||||
|
||||
class AttributeTemplateService:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
async def get_template(self, template_id: int) -> Dict:
|
||||
"""获取模板及其属性定义"""
|
||||
result = await self.db.execute(
|
||||
select(AttributeTemplate)
|
||||
.where(AttributeTemplate.id == template_id)
|
||||
)
|
||||
template = result.scalar_one()
|
||||
|
||||
result = await self.db.execute(
|
||||
select(AttributeDefinition)
|
||||
.where(AttributeDefinition.template_id == template_id)
|
||||
.order_by(AttributeDefinition.sort_order)
|
||||
)
|
||||
definitions = result.scalars().all()
|
||||
|
||||
return {
|
||||
"id": template.id,
|
||||
"name": template.name,
|
||||
"attributes": [
|
||||
{
|
||||
"name": d.name,
|
||||
"label": d.label,
|
||||
"type": d.type,
|
||||
"required": d.required,
|
||||
"default_value": d.default_value,
|
||||
"validation_rule": d.validation_rule,
|
||||
"options": d.options
|
||||
}
|
||||
for d in definitions
|
||||
]
|
||||
}
|
||||
|
||||
async def validate_attributes(
|
||||
self,
|
||||
template_id: int,
|
||||
attributes: Dict
|
||||
) -> Dict:
|
||||
"""验证属性值"""
|
||||
template = await self.get_template(template_id)
|
||||
errors = []
|
||||
|
||||
for attr_def in template["attributes"]:
|
||||
name = attr_def["name"]
|
||||
value = attributes.get(name)
|
||||
|
||||
# 必填校验
|
||||
if attr_def["required"] and not value:
|
||||
errors.append(f"{attr_def['label']} 不能为空")
|
||||
continue
|
||||
|
||||
# 类型校验
|
||||
if value:
|
||||
try:
|
||||
if attr_def["type"] == "number":
|
||||
float(value)
|
||||
elif attr_def["type"] == "select":
|
||||
if value not in (attr_def["options"] or []):
|
||||
errors.append(f"{attr_def['label']} 值无效")
|
||||
except ValueError:
|
||||
errors.append(f"{attr_def['label']} 类型错误")
|
||||
|
||||
return {"valid": len(errors) == 0, "errors": errors}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、M1-011:批量导入导出功能
|
||||
|
||||
### 6.1 导入服务
|
||||
|
||||
```python
|
||||
# services/import_export_service.py
|
||||
import pandas as pd
|
||||
from io import BytesIO
|
||||
from typing import List, Dict
|
||||
from fastapi import UploadFile
|
||||
|
||||
class ImportExportService:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
async def import_products(
|
||||
self,
|
||||
file: UploadFile,
|
||||
update_existing: bool = False
|
||||
) -> Dict:
|
||||
"""导入产品"""
|
||||
# 读取Excel
|
||||
content = await file.read()
|
||||
df = pd.read_excel(BytesIO(content))
|
||||
|
||||
results = {
|
||||
"total": len(df),
|
||||
"success": 0,
|
||||
"failed": 0,
|
||||
"errors": []
|
||||
}
|
||||
|
||||
for index, row in df.iterrows():
|
||||
try:
|
||||
# 验证数据
|
||||
validation = self._validate_row(row)
|
||||
if not validation["valid"]:
|
||||
results["errors"].append({
|
||||
"row": index + 2,
|
||||
"code": row.get("code"),
|
||||
"error": validation["error"]
|
||||
})
|
||||
results["failed"] += 1
|
||||
continue
|
||||
|
||||
# 创建或更新产品
|
||||
await self._create_or_update_product(row, update_existing)
|
||||
results["success"] += 1
|
||||
|
||||
except Exception as e:
|
||||
results["errors"].append({
|
||||
"row": index + 2,
|
||||
"code": row.get("code"),
|
||||
"error": str(e)
|
||||
})
|
||||
results["failed"] += 1
|
||||
|
||||
await self.db.commit()
|
||||
return results
|
||||
|
||||
async def export_products(
|
||||
self,
|
||||
product_ids: List[int] = None,
|
||||
category_id: int = None,
|
||||
format: str = "xlsx"
|
||||
) -> BytesIO:
|
||||
"""导出产品"""
|
||||
# 查询产品
|
||||
query = select(Product)
|
||||
if product_ids:
|
||||
query = query.where(Product.id.in_(product_ids))
|
||||
if category_id:
|
||||
query = query.where(Product.category_id == category_id)
|
||||
|
||||
result = await self.db.execute(query)
|
||||
products = result.scalars().all()
|
||||
|
||||
# 转换为DataFrame
|
||||
data = [
|
||||
{
|
||||
"编码": p.code,
|
||||
"名称": p.name,
|
||||
"描述": p.description,
|
||||
"分类": p.category.name if p.category else "",
|
||||
"状态": p.status,
|
||||
"规格": str(p.specifications) if p.specifications else ""
|
||||
}
|
||||
for p in products
|
||||
]
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
# 导出
|
||||
output = BytesIO()
|
||||
if format == "xlsx":
|
||||
df.to_excel(output, index=False)
|
||||
else:
|
||||
df.to_csv(output, index=False)
|
||||
|
||||
output.seek(0)
|
||||
return output
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、M1-012:数据校验规则引擎
|
||||
|
||||
### 7.1 规则引擎设计
|
||||
|
||||
```python
|
||||
# services/validation_engine.py
|
||||
from typing import Dict, List, Any
|
||||
import re
|
||||
|
||||
class ValidationRule:
|
||||
def __init__(self, rule_type: str, params: Dict):
|
||||
self.rule_type = rule_type
|
||||
self.params = params
|
||||
|
||||
def validate(self, value: Any) -> Dict:
|
||||
"""执行校验"""
|
||||
pass
|
||||
|
||||
|
||||
class RequiredRule(ValidationRule):
|
||||
def validate(self, value: Any) -> Dict:
|
||||
if value is None or value == "":
|
||||
return {"valid": False, "error": "字段不能为空"}
|
||||
return {"valid": True}
|
||||
|
||||
|
||||
class PatternRule(ValidationRule):
|
||||
def validate(self, value: Any) -> Dict:
|
||||
pattern = self.params.get("pattern")
|
||||
if not re.match(pattern, str(value)):
|
||||
return {
|
||||
"valid": False,
|
||||
"error": self.params.get("message", "格式不正确")
|
||||
}
|
||||
return {"valid": True}
|
||||
|
||||
|
||||
class RangeRule(ValidationRule):
|
||||
def validate(self, value: Any) -> Dict:
|
||||
min_val = self.params.get("min")
|
||||
max_val = self.params.get("max")
|
||||
|
||||
try:
|
||||
num = float(value)
|
||||
if min_val is not None and num < min_val:
|
||||
return {"valid": False, "error": f"值不能小于{min_val}"}
|
||||
if max_val is not None and num > max_val:
|
||||
return {"valid": False, "error": f"值不能大于{max_val}"}
|
||||
return {"valid": True}
|
||||
except ValueError:
|
||||
return {"valid": False, "error": "不是有效的数字"}
|
||||
|
||||
|
||||
class ValidationEngine:
|
||||
RULE_TYPES = {
|
||||
"required": RequiredRule,
|
||||
"pattern": PatternRule,
|
||||
"range": RangeRule
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.rules: Dict[str, List[ValidationRule]] = {}
|
||||
|
||||
def add_rule(self, field: str, rule_type: str, params: Dict = None):
|
||||
"""添加校验规则"""
|
||||
if field not in self.rules:
|
||||
self.rules[field] = []
|
||||
|
||||
rule_class = self.RULE_TYPES.get(rule_type)
|
||||
if rule_class:
|
||||
self.rules[field].append(rule_class(rule_type, params or {}))
|
||||
|
||||
def validate(self, data: Dict) -> Dict:
|
||||
"""校验数据"""
|
||||
errors = {}
|
||||
|
||||
for field, rules in self.rules.items():
|
||||
value = data.get(field)
|
||||
for rule in rules:
|
||||
result = rule.validate(value)
|
||||
if not result["valid"]:
|
||||
if field not in errors:
|
||||
errors[field] = []
|
||||
errors[field].append(result["error"])
|
||||
|
||||
return {
|
||||
"valid": len(errors) == 0,
|
||||
"errors": errors
|
||||
}
|
||||
|
||||
|
||||
# 使用示例
|
||||
engine = ValidationEngine()
|
||||
engine.add_rule("code", "required")
|
||||
engine.add_rule("code", "pattern", {
|
||||
"pattern": r"^P\d{3,}$",
|
||||
"message": "编码格式:P开头+至少3位数字"
|
||||
})
|
||||
engine.add_rule("weight", "range", {"min": 0, "max": 10000})
|
||||
|
||||
result = engine.validate({
|
||||
"code": "P001",
|
||||
"weight": 150
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、测试用例
|
||||
|
||||
### 8.1 BOM服务测试
|
||||
|
||||
```python
|
||||
# tests/test_bom_service.py
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
from app.main import app
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_bom():
|
||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
||||
response = await client.post(
|
||||
"/api/v1/boms",
|
||||
json={
|
||||
"product_id": 1,
|
||||
"code": "BOM-TEST-001",
|
||||
"name": "测试BOM",
|
||||
"type": "manufacturing",
|
||||
"items": [
|
||||
{
|
||||
"material_code": "M001",
|
||||
"material_name": "测试物料",
|
||||
"quantity": 10,
|
||||
"unit": "pcs",
|
||||
"level": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["code"] == "BOM-TEST-001"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_expand_bom():
|
||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
||||
# 先创建BOM
|
||||
# ...
|
||||
|
||||
# 测试展开
|
||||
response = await client.get("/api/v1/boms/1/expand?level=-1")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "items" in data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、交付清单
|
||||
|
||||
### 9.1 代码交付
|
||||
|
||||
- [ ] BOM数据模型(models/bom.py)
|
||||
- [ ] BOM API路由(api/bom_router.py)
|
||||
- [ ] BOM业务服务(services/bom_service.py)
|
||||
- [ ] BOM树形组件(views/BOM/BOMTree.vue)
|
||||
- [ ] 属性模板服务
|
||||
- [ ] 导入导出服务
|
||||
- [ ] 校验规则引擎
|
||||
|
||||
### 9.2 文档交付
|
||||
|
||||
- [ ] API接口文档
|
||||
- [ ] 数据库设计文档
|
||||
- [ ] 组件使用文档
|
||||
- [ ] 测试报告
|
||||
|
||||
### 9.3 验收标准
|
||||
|
||||
| 验收项 | 标准 |
|
||||
|--------|------|
|
||||
| 功能完整性 | 6项任务全部完成 |
|
||||
| API测试覆盖率 | > 80% |
|
||||
| 前端组件可运行 | 无报错 |
|
||||
| 数据校验有效 | 所有规则生效 |
|
||||
|
||||
---
|
||||
|
||||
## 十、风险与应对
|
||||
|
||||
| 风险 | 影响 | 应对措施 |
|
||||
|------|------|----------|
|
||||
| BOM层级过深 | 性能问题 | 使用C++引擎优化 |
|
||||
| 导入数据量大 | 内存溢出 | 分批处理+流式导入 |
|
||||
| 校验规则复杂 | 维护困难 | 规则配置化管理 |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 20:45_
|
||||
_维护人:笔杆子 (creator)_
|
||||
743
development/PLM开发手册.md
Normal file
743
development/PLM开发手册.md
Normal file
@@ -0,0 +1,743 @@
|
||||
# PLM 系统开发手册
|
||||
|
||||
> **版本**:V1.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子 (creator)
|
||||
> **状态**:已发布
|
||||
|
||||
---
|
||||
|
||||
## 第一章 快速开始
|
||||
|
||||
### 1.1 项目概述
|
||||
|
||||
PLM(Product Lifecycle Management)系统是一套产品生命周期管理系统,采用AI原生架构设计。
|
||||
|
||||
**项目位置:** `/home/serveradmin/plm-system/`
|
||||
|
||||
**技术栈:**
|
||||
- 后端:Python 3.11 + FastAPI
|
||||
- 前端:Vue 3 + TypeScript
|
||||
- 数据库:PostgreSQL 16 + pgvector
|
||||
- 通信:gRPC + Protobuf
|
||||
|
||||
### 1.2 环境要求
|
||||
|
||||
| 软件 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| Python | 3.11+ | 后端运行环境 |
|
||||
| Node.js | 18+ | 前端运行环境 |
|
||||
| PostgreSQL | 16 | 主数据库 |
|
||||
| Redis | 7 | 缓存服务 |
|
||||
| Docker | 24+ | 容器化部署 |
|
||||
|
||||
### 1.3 快速启动
|
||||
|
||||
```bash
|
||||
# 1. 克隆代码
|
||||
git clone http://192.168.3.36:3000/plm-team/plm-backend-service.git
|
||||
|
||||
# 2. 进入项目目录
|
||||
cd plm-backend-service
|
||||
|
||||
# 3. 创建虚拟环境
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
# 4. 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 5. 配置环境变量
|
||||
cp .env.example .env
|
||||
# 编辑 .env 文件
|
||||
|
||||
# 6. 启动服务
|
||||
python3 -m app.main
|
||||
|
||||
# 7. 访问API文档
|
||||
open http://localhost:8000/docs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第二章 项目结构
|
||||
|
||||
### 2.1 后端项目结构
|
||||
|
||||
```
|
||||
plm-backend-service/
|
||||
├── app/
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py # FastAPI应用入口
|
||||
│ ├── init_db.py # 数据库初始化
|
||||
│ ├── core/ # 核心模块
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── config.py # 配置管理
|
||||
│ │ ├── database.py # 数据库连接
|
||||
│ │ ├── security.py # 安全认证
|
||||
│ │ └── redis.py # Redis缓存
|
||||
│ ├── models/ # ORM模型
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── user.py # 用户模型
|
||||
│ │ ├── product.py # 产品模型
|
||||
│ │ ├── bom.py # BOM模型
|
||||
│ │ └── document.py # 文档模型
|
||||
│ ├── schemas/ # Pydantic模型
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── common.py # 公共模型
|
||||
│ │ ├── user.py # 用户Schema
|
||||
│ │ ├── product.py # 产品Schema
|
||||
│ │ └── bom.py # BOM Schema
|
||||
│ ├── api/ # API路由
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── auth.py # 认证路由
|
||||
│ │ ├── users.py # 用户路由
|
||||
│ │ ├── products.py # 产品路由
|
||||
│ │ └── boms.py # BOM路由
|
||||
│ └── services/ # 业务逻辑
|
||||
│ ├── __init__.py
|
||||
│ ├── user_service.py
|
||||
│ ├── product_service.py
|
||||
│ └── bom_service.py
|
||||
├── tests/ # 测试用例
|
||||
│ ├── __init__.py
|
||||
│ ├── conftest.py # 测试配置
|
||||
│ └── test_api.py # API测试
|
||||
├── alembic/ # 数据库迁移
|
||||
│ ├── versions/
|
||||
│ └── env.py
|
||||
├── .env.example # 环境变量模板
|
||||
├── requirements.txt # Python依赖
|
||||
├── Dockerfile # Docker构建
|
||||
├── docker-compose.yml # 容器编排
|
||||
├── .drone.yml # CI/CD配置
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
### 2.2 前端项目结构
|
||||
|
||||
```
|
||||
plm-web-frontend/
|
||||
├── src/
|
||||
│ ├── main.ts # 应用入口
|
||||
│ ├── App.vue # 根组件
|
||||
│ ├── router/ # 路由配置
|
||||
│ │ └── index.ts
|
||||
│ ├── store/ # 状态管理
|
||||
│ │ ├── index.ts
|
||||
│ │ └── modules/
|
||||
│ ├── views/ # 页面组件
|
||||
│ │ ├── Login.vue
|
||||
│ │ ├── Dashboard.vue
|
||||
│ │ ├── Products/
|
||||
│ │ ├── BOMs/
|
||||
│ │ └── Documents/
|
||||
│ ├── components/ # 公共组件
|
||||
│ │ ├── common/
|
||||
│ │ └── ai/ # AI交互组件
|
||||
│ ├── api/ # API调用
|
||||
│ │ ├── auth.ts
|
||||
│ │ ├── products.ts
|
||||
│ │ └── boms.ts
|
||||
│ ├── utils/ # 工具函数
|
||||
│ │ ├── request.ts # HTTP封装
|
||||
│ │ └── auth.ts # 认证工具
|
||||
│ └── styles/ # 样式文件
|
||||
├── public/ # 静态资源
|
||||
├── package.json # 依赖配置
|
||||
├── vite.config.ts # Vite配置
|
||||
├── tsconfig.json # TS配置
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第三章 环境配置
|
||||
|
||||
### 3.1 环境变量配置
|
||||
|
||||
创建 `.env` 文件:
|
||||
|
||||
```bash
|
||||
# 应用配置
|
||||
APP_NAME=PLM System
|
||||
APP_ENV=development
|
||||
APP_DEBUG=true
|
||||
APP_PORT=8000
|
||||
|
||||
# 数据库配置
|
||||
DATABASE_URL=postgresql://plm:plm123@localhost:5432/plm_db
|
||||
DATABASE_POOL_SIZE=10
|
||||
DATABASE_MAX_OVERFLOW=20
|
||||
|
||||
# Redis配置
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
|
||||
# JWT配置
|
||||
JWT_SECRET_KEY=your-secret-key-change-in-production
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
|
||||
# AI服务配置
|
||||
AI_API_KEY=your-openai-api-key
|
||||
AI_MODEL=gpt-4
|
||||
AI_EMBEDDING_MODEL=text-embedding-3-small
|
||||
|
||||
# 文件存储配置
|
||||
STORAGE_TYPE=minio
|
||||
MINIO_ENDPOINT=localhost:9000
|
||||
MINIO_ACCESS_KEY=minioadmin
|
||||
MINIO_SECRET_KEY=minioadmin
|
||||
MINIO_BUCKET=plm-documents
|
||||
|
||||
# gRPC配置
|
||||
GRPC_PORT=50051
|
||||
|
||||
# 日志配置
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FILE=logs/app.log
|
||||
```
|
||||
|
||||
### 3.2 Docker Compose配置
|
||||
|
||||
`docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
environment:
|
||||
POSTGRES_USER: plm
|
||||
POSTGRES_PASSWORD: plm123
|
||||
POSTGRES_DB: plm_db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:7
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
minio:
|
||||
image: minio/minio
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: minioadmin
|
||||
MINIO_ROOT_PASSWORD: minioadmin
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
|
||||
backend:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
DATABASE_URL: postgresql://plm:plm123@postgres:5432/plm_db
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
minio_data:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第四章 编码规范
|
||||
|
||||
### 4.1 Python编码规范
|
||||
|
||||
#### 4.1.1 命名规范
|
||||
|
||||
```python
|
||||
# 模块名:snake_case
|
||||
# user_service.py
|
||||
|
||||
# 类名:PascalCase
|
||||
class UserService:
|
||||
pass
|
||||
|
||||
# 函数/方法名:snake_case
|
||||
def get_user_by_id(user_id: int) -> User:
|
||||
pass
|
||||
|
||||
# 变量名:snake_case
|
||||
user_name = "admin"
|
||||
|
||||
# 常量:UPPER_SNAKE_CASE
|
||||
MAX_RETRY_COUNT = 3
|
||||
DEFAULT_PAGE_SIZE = 20
|
||||
|
||||
# 私有属性:_前缀
|
||||
class User:
|
||||
def __init__(self):
|
||||
self._internal_id = None
|
||||
```
|
||||
|
||||
#### 4.1.2 类型注解
|
||||
|
||||
```python
|
||||
from typing import List, Optional, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
def create_user(
|
||||
username: str,
|
||||
email: str,
|
||||
role: str = "user",
|
||||
department_id: Optional[int] = None
|
||||
) -> User:
|
||||
"""创建用户"""
|
||||
pass
|
||||
|
||||
def get_users(
|
||||
page: int = 1,
|
||||
page_size: int = 20
|
||||
) -> Dict[str, Any]:
|
||||
"""获取用户列表"""
|
||||
return {
|
||||
"items": [],
|
||||
"total": 0
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.1.3 文档字符串
|
||||
|
||||
```python
|
||||
def calculate_bom_cost(bom_id: int) -> float:
|
||||
"""
|
||||
计算BOM成本
|
||||
|
||||
Args:
|
||||
bom_id: BOM ID
|
||||
|
||||
Returns:
|
||||
float: 总成本
|
||||
|
||||
Raises:
|
||||
ValueError: BOM不存在时
|
||||
|
||||
Example:
|
||||
>>> cost = calculate_bom_cost(1)
|
||||
>>> print(cost)
|
||||
1234.56
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
#### 4.1.4 异常处理
|
||||
|
||||
```python
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
def get_product(product_id: int) -> Product:
|
||||
product = product_repo.get(product_id)
|
||||
if not product:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Product {product_id} not found"
|
||||
)
|
||||
return product
|
||||
```
|
||||
|
||||
### 4.2 TypeScript编码规范
|
||||
|
||||
#### 4.2.1 命名规范
|
||||
|
||||
```typescript
|
||||
// 文件名:kebab-case
|
||||
// user-service.ts
|
||||
|
||||
// 接口/类名:PascalCase
|
||||
interface UserInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
class UserService {
|
||||
// ...
|
||||
}
|
||||
|
||||
// 函数/变量:camelCase
|
||||
function getUserById(userId: number): Promise<UserInfo> {
|
||||
// ...
|
||||
}
|
||||
|
||||
const userName = "admin";
|
||||
|
||||
// 常量:UPPER_SNAKE_CASE
|
||||
export const MAX_PAGE_SIZE = 20;
|
||||
|
||||
// 枚举:PascalCase
|
||||
enum UserStatus {
|
||||
Active = 'active',
|
||||
Inactive = 'inactive'
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.2 组件规范
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="user-list">
|
||||
<el-table :data="users">
|
||||
<el-table-column prop="name" label="用户名" />
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getUsers } from '@/api/users'
|
||||
|
||||
interface User {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
|
||||
const users = ref<User[]>([])
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await getUsers()
|
||||
users.value = res.data.items
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.user-list {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第五章 API开发指南
|
||||
|
||||
### 5.1 创建新API
|
||||
|
||||
#### 步骤1:定义Schema
|
||||
|
||||
```python
|
||||
# app/schemas/product.py
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
class ProductBase(BaseModel):
|
||||
code: str = Field(..., description="产品编码")
|
||||
name: str = Field(..., description="产品名称")
|
||||
description: Optional[str] = Field(None, description="产品描述")
|
||||
category_id: int = Field(..., description="分类ID")
|
||||
|
||||
class ProductCreate(ProductBase):
|
||||
pass
|
||||
|
||||
class ProductUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
status: Optional[str] = None
|
||||
|
||||
class ProductResponse(ProductBase):
|
||||
id: int
|
||||
status: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
```
|
||||
|
||||
#### 步骤2:定义Model
|
||||
|
||||
```python
|
||||
# app/models/product.py
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Text
|
||||
from sqlalchemy.sql import func
|
||||
from app.core.database import Base
|
||||
|
||||
class Product(Base):
|
||||
__tablename__ = "products"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
code = Column(String(50), unique=True, index=True)
|
||||
name = Column(String(200), nullable=False)
|
||||
description = Column(Text)
|
||||
category_id = Column(Integer, index=True)
|
||||
status = Column(String(20), default="draft")
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
```
|
||||
|
||||
#### 步骤3:创建路由
|
||||
|
||||
```python
|
||||
# app/api/products.py
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from typing import List
|
||||
from app.schemas.product import ProductCreate, ProductResponse
|
||||
from app.services.product_service import ProductService
|
||||
|
||||
router = APIRouter(prefix="/products", tags=["Products"])
|
||||
|
||||
@router.get("/", response_model=List[ProductResponse])
|
||||
async def list_products(
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
service: ProductService = Depends()
|
||||
):
|
||||
"""获取产品列表"""
|
||||
return await service.get_products(page, page_size)
|
||||
|
||||
@router.post("/", response_model=ProductResponse)
|
||||
async def create_product(
|
||||
product: ProductCreate,
|
||||
service: ProductService = Depends()
|
||||
):
|
||||
"""创建产品"""
|
||||
return await service.create_product(product)
|
||||
|
||||
@router.get("/{product_id}", response_model=ProductResponse)
|
||||
async def get_product(
|
||||
product_id: int,
|
||||
service: ProductService = Depends()
|
||||
):
|
||||
"""获取产品详情"""
|
||||
product = await service.get_product(product_id)
|
||||
if not product:
|
||||
raise HTTPException(status_code=404, detail="Product not found")
|
||||
return product
|
||||
```
|
||||
|
||||
#### 步骤4:注册路由
|
||||
|
||||
```python
|
||||
# app/main.py
|
||||
from fastapi import FastAPI
|
||||
from app.api import products, users, auth
|
||||
|
||||
app = FastAPI(title="PLM System")
|
||||
|
||||
app.include_router(auth.router)
|
||||
app.include_router(users.router)
|
||||
app.include_router(products.router)
|
||||
```
|
||||
|
||||
### 5.2 认证中间件
|
||||
|
||||
```python
|
||||
# app/core/security.py
|
||||
from fastapi import Depends, HTTPException
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from jose import JWTError, jwt
|
||||
|
||||
security = HTTPBearer()
|
||||
|
||||
async def get_current_user(
|
||||
credentials: HTTPAuthorizationCredentials = Depends(security)
|
||||
):
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
credentials.credentials,
|
||||
settings.JWT_SECRET_KEY,
|
||||
algorithms=[settings.JWT_ALGORITHM]
|
||||
)
|
||||
user_id = payload.get("sub")
|
||||
if user_id is None:
|
||||
raise HTTPException(status_code=401, detail="Invalid token")
|
||||
return user_id
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Invalid token")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第六章 测试指南
|
||||
|
||||
### 6.1 单元测试
|
||||
|
||||
```python
|
||||
# tests/test_products.py
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
from app.main import app
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_products():
|
||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
||||
response = await client.get("/products")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "items" in data
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_product():
|
||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
||||
response = await client.post(
|
||||
"/products",
|
||||
json={
|
||||
"code": "P001",
|
||||
"name": "Test Product",
|
||||
"category_id": 1
|
||||
}
|
||||
)
|
||||
assert response.status_code == 201
|
||||
```
|
||||
|
||||
### 6.2 运行测试
|
||||
|
||||
```bash
|
||||
# 运行所有测试
|
||||
pytest
|
||||
|
||||
# 运行指定测试文件
|
||||
pytest tests/test_products.py
|
||||
|
||||
# 带覆盖率
|
||||
pytest --cov=app tests/
|
||||
|
||||
# 生成HTML报告
|
||||
pytest --cov=app --cov-report=html tests/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第七章 部署指南
|
||||
|
||||
### 7.1 Docker部署
|
||||
|
||||
```bash
|
||||
# 构建镜像
|
||||
docker build -t plm-backend:latest .
|
||||
|
||||
# 运行容器
|
||||
docker run -d \
|
||||
--name plm-backend \
|
||||
-p 8000:8000 \
|
||||
--env-file .env \
|
||||
plm-backend:latest
|
||||
|
||||
# 查看日志
|
||||
docker logs -f plm-backend
|
||||
```
|
||||
|
||||
### 7.2 Kubernetes部署
|
||||
|
||||
```yaml
|
||||
# k8s/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: plm-backend
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: plm-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: plm-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: plm-backend
|
||||
image: plm-backend:latest
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: plm-config
|
||||
- secretRef:
|
||||
name: plm-secrets
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第八章 常见问题
|
||||
|
||||
### 8.1 数据库连接问题
|
||||
|
||||
```bash
|
||||
# 检查PostgreSQL状态
|
||||
sudo systemctl status postgresql
|
||||
|
||||
# 检查连接
|
||||
psql -h localhost -U plm -d plm_db
|
||||
|
||||
# 常见错误
|
||||
# 1. Connection refused -> 检查PostgreSQL是否启动
|
||||
# 2. Authentication failed -> 检查用户名密码
|
||||
# 3. Database not found -> 检查数据库是否创建
|
||||
```
|
||||
|
||||
### 8.2 JWT Token问题
|
||||
|
||||
```python
|
||||
# Token过期
|
||||
# 解决:刷新Token或重新登录
|
||||
|
||||
# Token无效
|
||||
# 解决:检查JWT_SECRET_KEY是否一致
|
||||
```
|
||||
|
||||
### 8.3 CORS问题
|
||||
|
||||
```python
|
||||
# app/main.py
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:5173"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第九章 附录
|
||||
|
||||
### 9.1 常用命令
|
||||
|
||||
```bash
|
||||
# 后端
|
||||
uvicorn app.main:app --reload # 开发模式
|
||||
pytest # 运行测试
|
||||
alembic revision --autogenerate # 生成迁移
|
||||
alembic upgrade head # 执行迁移
|
||||
|
||||
# 前端
|
||||
npm run dev # 开发模式
|
||||
npm run build # 构建生产版本
|
||||
npm run lint # 代码检查
|
||||
npm run test # 运行测试
|
||||
|
||||
# Docker
|
||||
docker-compose up -d # 启动服务
|
||||
docker-compose down # 停止服务
|
||||
docker-compose logs -f # 查看日志
|
||||
```
|
||||
|
||||
### 9.2 联系方式
|
||||
|
||||
| 角色 | 姓名 | 职责 |
|
||||
|------|------|------|
|
||||
| CTO | 进化官 | 技术决策 |
|
||||
| 研发总监 | tech-lead | 代码审核 |
|
||||
| 文档总监 | 笔杆子 | 文档维护 |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 20:20_
|
||||
_维护人:笔杆子 (creator)_
|
||||
354
development/PLM开发文档.md
Normal file
354
development/PLM开发文档.md
Normal file
@@ -0,0 +1,354 @@
|
||||
# PLM 开发文档
|
||||
|
||||
> **版本**:V1.0
|
||||
> **创建时间**:2026-03-31
|
||||
> **创建人**:笔杆子
|
||||
> **状态**:草稿
|
||||
|
||||
---
|
||||
|
||||
## 一、技术栈
|
||||
|
||||
### 1.1 后端技术栈
|
||||
|
||||
| 技术 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| Python | 3.11 | 主要开发语言 |
|
||||
| FastAPI | 0.100+ | Web框架 |
|
||||
| SQLAlchemy | 2.0 | ORM框架 |
|
||||
| Pydantic | 2.0 | 数据验证 |
|
||||
| gRPC | - | 微服务通信 |
|
||||
| PostgreSQL | 16 | 主数据库 |
|
||||
| Redis | 7 | 缓存 |
|
||||
| RabbitMQ | 3.12 | 消息队列 |
|
||||
|
||||
### 1.2 前端技术栈
|
||||
|
||||
| 技术 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| Vue | 3.4+ | 前端框架 |
|
||||
| TypeScript | 5.0 | 类型支持 |
|
||||
| Element Plus | 2.5 | UI组件库 |
|
||||
| Pinia | 2.1 | 状态管理 |
|
||||
| Axios | 1.6 | HTTP客户端 |
|
||||
| ECharts | 5.4 | 数据可视化 |
|
||||
|
||||
### 1.3 C++ 引擎层
|
||||
|
||||
| 技术 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| C++ | 17/20 | 高性能计算 |
|
||||
| pybind11 | - | Python绑定 |
|
||||
|
||||
---
|
||||
|
||||
## 二、开发环境搭建
|
||||
|
||||
### 2.1 系统要求
|
||||
|
||||
- OS: Ubuntu 22.04 / Windows 11
|
||||
- Python: 3.11+
|
||||
- Node.js: 18+
|
||||
- Docker: 24+
|
||||
- PostgreSQL: 16
|
||||
|
||||
### 2.2 后端环境配置
|
||||
|
||||
```bash
|
||||
# 克隆代码
|
||||
git clone http://192.168.3.36:3000/plm-team/plm-backend-service.git
|
||||
|
||||
# 创建虚拟环境
|
||||
cd plm-backend-service
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 配置环境变量
|
||||
cp .env.example .env
|
||||
# 编辑 .env 文件
|
||||
|
||||
# 启动服务
|
||||
python3 -m app.main
|
||||
```
|
||||
|
||||
### 2.3 前端环境配置
|
||||
|
||||
```bash
|
||||
# 克隆代码
|
||||
git clone http://192.168.3.36:3000/plm-team/plm-web-frontend.git
|
||||
|
||||
# 安装依赖
|
||||
cd plm-web-frontend
|
||||
npm install
|
||||
|
||||
# 启动开发服务器
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 2.4 Docker 环境配置
|
||||
|
||||
```bash
|
||||
# 启动所有服务
|
||||
docker-compose up -d
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、项目结构
|
||||
|
||||
### 3.1 后端项目结构
|
||||
|
||||
```
|
||||
plm-backend-service/
|
||||
├── app/
|
||||
│ ├── main.py # 应用入口
|
||||
│ ├── core/ # 核心配置
|
||||
│ │ ├── config.py # 配置管理
|
||||
│ │ ├── database.py # 数据库连接
|
||||
│ │ └── security.py # 安全认证
|
||||
│ ├── models/ # 数据模型
|
||||
│ ├── schemas/ # 数据验证
|
||||
│ ├── api/ # API路由
|
||||
│ └── services/ # 业务逻辑
|
||||
├── tests/ # 测试用例
|
||||
├── .env.example # 环境变量模板
|
||||
├── requirements.txt # Python依赖
|
||||
├── Dockerfile # Docker构建
|
||||
└── docker-compose.yml # 容器编排
|
||||
```
|
||||
|
||||
### 3.2 前端项目结构
|
||||
|
||||
```
|
||||
plm-web-frontend/
|
||||
├── src/
|
||||
│ ├── main.ts # 应用入口
|
||||
│ ├── App.vue # 根组件
|
||||
│ ├── router/ # 路由配置
|
||||
│ ├── store/ # 状态管理
|
||||
│ ├── views/ # 页面组件
|
||||
│ ├── components/ # 公共组件
|
||||
│ ├── api/ # API调用
|
||||
│ └── utils/ # 工具函数
|
||||
├── public/ # 静态资源
|
||||
├── package.json # 依赖配置
|
||||
└── vite.config.ts # Vite配置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、编码规范
|
||||
|
||||
### 4.1 Python 编码规范
|
||||
|
||||
```python
|
||||
# 文件命名:snake_case
|
||||
# 类名:PascalCase
|
||||
# 函数/变量:snake_case
|
||||
# 常量:UPPER_SNAKE_CASE
|
||||
|
||||
# 示例
|
||||
class UserService:
|
||||
def get_user_by_id(self, user_id: int) -> User:
|
||||
pass
|
||||
|
||||
MAX_RETRY_COUNT = 3
|
||||
```
|
||||
|
||||
### 4.2 TypeScript 编码规范
|
||||
|
||||
```typescript
|
||||
// 文件命名:kebab-case
|
||||
// 类名/接口:PascalCase
|
||||
// 函数/变量:camelCase
|
||||
// 常量:UPPER_SNAKE_CASE
|
||||
|
||||
// 示例
|
||||
interface UserInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export function getUserById(userId: number): Promise<UserInfo> {
|
||||
// ...
|
||||
}
|
||||
|
||||
export const MAX_PAGE_SIZE = 20;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、Git 工作流
|
||||
|
||||
### 5.1 分支策略
|
||||
|
||||
```
|
||||
main # 生产分支,稳定版本
|
||||
develop # 开发分支,集成测试
|
||||
feature/* # 功能分支,开发新功能
|
||||
bugfix/* # 修复分支,修复Bug
|
||||
release/* # 发布分支,版本发布
|
||||
```
|
||||
|
||||
### 5.2 提交规范
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
type:
|
||||
- feat: 新功能
|
||||
- fix: 修复Bug
|
||||
- docs: 文档更新
|
||||
- style: 代码格式
|
||||
- refactor: 重构
|
||||
- test: 测试
|
||||
- chore: 构建/工具
|
||||
|
||||
示例:
|
||||
feat(auth): add JWT authentication
|
||||
fix(api): resolve pagination issue
|
||||
docs(readme): update installation guide
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、代码审查规范
|
||||
|
||||
### 6.1 审查清单
|
||||
|
||||
- [ ] 代码是否符合编码规范
|
||||
- [ ] 是否有足够的注释
|
||||
- [ ] 是否有单元测试
|
||||
- [ ] 是否有安全风险
|
||||
- [ ] 性能是否可接受
|
||||
- [ ] 是否有重复代码
|
||||
|
||||
### 6.2 审查流程
|
||||
|
||||
1. 开发者提交 Pull Request
|
||||
2. 自动运行 CI 测试
|
||||
3. 至少1人审核通过
|
||||
4. 合并到目标分支
|
||||
|
||||
---
|
||||
|
||||
## 七、测试规范
|
||||
|
||||
### 7.1 单元测试
|
||||
|
||||
```python
|
||||
# tests/test_user.py
|
||||
import pytest
|
||||
from app.services.user_service import UserService
|
||||
|
||||
def test_create_user():
|
||||
service = UserService()
|
||||
user = service.create_user(
|
||||
username="test",
|
||||
email="test@example.com"
|
||||
)
|
||||
assert user.username == "test"
|
||||
```
|
||||
|
||||
### 7.2 测试覆盖率
|
||||
|
||||
- 目标覆盖率:80%+
|
||||
- 核心模块覆盖率:90%+
|
||||
|
||||
---
|
||||
|
||||
## 八、部署规范
|
||||
|
||||
### 8.1 环境变量
|
||||
|
||||
```bash
|
||||
# 数据库
|
||||
DATABASE_URL=postgresql://user:pass@localhost:5432/plm
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
|
||||
# JWT
|
||||
JWT_SECRET_KEY=your-secret-key
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
|
||||
# AI服务
|
||||
AI_API_KEY=your-api-key
|
||||
AI_MODEL=gpt-4
|
||||
```
|
||||
|
||||
### 8.2 Docker 部署
|
||||
|
||||
```bash
|
||||
# 构建镜像
|
||||
docker build -t plm-backend:latest .
|
||||
|
||||
# 运行容器
|
||||
docker run -d \
|
||||
--name plm-backend \
|
||||
-p 8000:8000 \
|
||||
--env-file .env \
|
||||
plm-backend:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、常用命令
|
||||
|
||||
### 9.1 后端命令
|
||||
|
||||
```bash
|
||||
# 启动开发服务器
|
||||
uvicorn app.main:app --reload
|
||||
|
||||
# 运行测试
|
||||
pytest
|
||||
|
||||
# 生成API文档
|
||||
# 自动生成,访问 /docs
|
||||
|
||||
# 数据库迁移
|
||||
alembic revision --autogenerate -m "message"
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
### 9.2 前端命令
|
||||
|
||||
```bash
|
||||
# 启动开发服务器
|
||||
npm run dev
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 运行测试
|
||||
npm run test
|
||||
|
||||
# 代码格式化
|
||||
npm run lint
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、联系方式
|
||||
|
||||
| 角色 | 姓名 | 职责 |
|
||||
|------|------|------|
|
||||
| CTO | 进化官 | 技术决策 |
|
||||
| 研发总监 | tech-lead | 代码审核 |
|
||||
| 文档总监 | 笔杆子 | 文档维护 |
|
||||
|
||||
---
|
||||
|
||||
_创建时间:2026-03-31 18:06_
|
||||
_维护人:笔杆子 (creator)_
|
||||
Reference in New Issue
Block a user