feat: 实现完整三级标题生成功能
- 扩展DocumentChapter模型支持嵌套结构和评分值 - 新增智能分组算法,按关键词和前缀对评分项进行分类 - 重写章节生成逻辑,支持一级、二级、三级标题完整结构 - 优化显示系统,支持递归显示和颜色区分 - 增强表格解析能力,处理复杂的合并单元格结构 - 改进AI识别逻辑,更好地识别评分表格类型 - 完善.gitignore文件,添加项目相关忽略规则 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
47fc26f3f0
commit
f48971cf67
59
.gitignore
vendored
59
.gitignore
vendored
@ -1,10 +1,63 @@
|
|||||||
# Python-generated files
|
# Python
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[oc]
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
build/
|
build/
|
||||||
|
develop-eggs/
|
||||||
dist/
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
wheels/
|
wheels/
|
||||||
*.egg-info
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
.env
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
.pytest_cache/
|
||||||
|
.coverage
|
||||||
|
.hypothesis/
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Claude Code
|
||||||
|
.claude/
|
||||||
|
|
||||||
|
# Project specific
|
||||||
|
data/kb/
|
||||||
|
*.docx
|
||||||
|
*.xlsx
|
||||||
|
*.csv
|
||||||
|
*.pdf
|
||||||
|
logs/
|
||||||
|
temp/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Ruff cache
|
||||||
|
.ruff_cache/
|
||||||
|
|||||||
4
data/README.md
Normal file
4
data/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# 数据存储目录
|
||||||
|
|
||||||
|
- kb/: 知识库数据(向量数据库)
|
||||||
|
- projects/: 项目数据存储
|
||||||
128
doc/江南造船厂前端.md
Normal file
128
doc/江南造船厂前端.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
这是一个基于Three.js的3D模型查看器和船厂三维数据管理展示系统。项目包含两个主要页面:
|
||||||
|
- `index.html`: 主要的3D模型查看器界面,支持模型加载、选择、测量、标注等功能
|
||||||
|
- `1.html`: 船舶建造精度数字化平台的数据分析界面,通过iframe嵌入3D查看器
|
||||||
|
|
||||||
|
## 技术架构
|
||||||
|
|
||||||
|
### 前端技术栈
|
||||||
|
- **Three.js**: 核心3D渲染引擎
|
||||||
|
- **原生JavaScript**: ES6+ 模块化架构,无框架依赖
|
||||||
|
- **HTML5/CSS3**: 响应式布局,使用Flexbox和Grid
|
||||||
|
- **Tailwind CSS**: 样式框架(仅在1.html中使用)
|
||||||
|
- **ECharts**: 数据可视化图表(仅在1.html中使用)
|
||||||
|
|
||||||
|
### 核心模块结构
|
||||||
|
|
||||||
|
所有JavaScript模块位于 `js/` 目录下,采用模块化设计:
|
||||||
|
|
||||||
|
#### 核心管理器
|
||||||
|
- **ModelViewer** (`main.js`): 主应用入口,管理整个3D场景
|
||||||
|
- **ModelManager** (`ModelManager.js`): 模型管理,处理模型的加载和切换
|
||||||
|
- **ModelLoader** (`ModelLoader.js`): 模型加载器,支持GLTF格式
|
||||||
|
- **ModelAPI** (`ModelAPI.js`): 模型API接口,提供程序化控制
|
||||||
|
|
||||||
|
#### 功能管理器
|
||||||
|
- **SelectionManager** (`SelectionManager.js`): 零件选择和高亮
|
||||||
|
- **MeasurementManager** (`MeasurementManager.js`): 3D测量工具(距离、角度、面积)
|
||||||
|
- **ClippingManager** (`ClippingManager.js`): 切面控制
|
||||||
|
- **AnnotationManager** (`AnnotationManager.js`): 3D标注功能
|
||||||
|
- **ModelTreeManager** (`ModelTreeManager.js`): 模型结构树管理
|
||||||
|
- **AnomalyDisplayManager** (`AnomalyDisplayManager.js`): 异常状态显示
|
||||||
|
- **LayerDisplayManager** (`LayerDisplayManager.js`): 分层显示管理
|
||||||
|
|
||||||
|
#### UI和状态管理
|
||||||
|
- **UIController** (`UIController.js`): UI控制器,管理所有界面交互
|
||||||
|
- **ObjectStateManager** (`ObjectStateManager.js`): 对象状态管理
|
||||||
|
- **StorageManager** (`StorageManager.js`): 本地存储管理
|
||||||
|
- **OutlineManager** (`OutlineManager.js`): 边缘高亮效果
|
||||||
|
|
||||||
|
### 资源结构
|
||||||
|
- **models/**: 3D模型文件(.glb格式)
|
||||||
|
- **css/**: 样式文件(主要是style.css)
|
||||||
|
- **image/**: UI图标和图片资源
|
||||||
|
- **three/**: Three.js库文件
|
||||||
|
|
||||||
|
## 开发环境
|
||||||
|
|
||||||
|
### 启动开发服务器
|
||||||
|
由于项目使用ES6模块和本地文件引用,需要通过HTTP服务器运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用Live Server(推荐)
|
||||||
|
# VS Code安装Live Server扩展,配置端口5501
|
||||||
|
# 右键点击index.html选择"Open with Live Server"
|
||||||
|
|
||||||
|
# 或使用Python内置服务器
|
||||||
|
python -m http.server 5501
|
||||||
|
|
||||||
|
# 或使用Node.js http-server
|
||||||
|
npx http-server -p 5501
|
||||||
|
```
|
||||||
|
|
||||||
|
### 访问页面
|
||||||
|
- 3D模型查看器: `http://localhost:5501/index.html`
|
||||||
|
- 数据分析平台: `http://localhost:5501/1.html`
|
||||||
|
|
||||||
|
## 开发约定
|
||||||
|
|
||||||
|
### 模型文件管理
|
||||||
|
- 支持的格式: .glb (推荐)
|
||||||
|
- 模型文件存放在 `models/` 目录
|
||||||
|
- 默认加载模型: `CX0856_CB01C.glb`
|
||||||
|
|
||||||
|
### 配置和状态管理
|
||||||
|
- 使用 `StorageManager` 进行本地存储
|
||||||
|
- 配置项通过 `ObjectStateManager` 管理
|
||||||
|
- 模型状态通过事件系统同步
|
||||||
|
|
||||||
|
### 代码风格
|
||||||
|
- 使用ES6+语法和模块
|
||||||
|
- 采用面向对象设计模式
|
||||||
|
- 每个功能模块独立文件
|
||||||
|
- 使用驼峰命名法
|
||||||
|
- 保持代码注释的完整性
|
||||||
|
|
||||||
|
### 事件通信
|
||||||
|
项目使用自定义事件系统进行模块间通信:
|
||||||
|
- 模型加载完成事件
|
||||||
|
- 选择状态变化事件
|
||||||
|
- UI状态更新事件
|
||||||
|
- 测量结果事件
|
||||||
|
|
||||||
|
### 浏览器兼容性
|
||||||
|
- 支持现代浏览器(Chrome 88+, Firefox 85+, Safari 14+)
|
||||||
|
- 依赖ES6模块支持
|
||||||
|
- 需要WebGL 2.0支持
|
||||||
|
|
||||||
|
## 调试和测试
|
||||||
|
|
||||||
|
### 控制台调试
|
||||||
|
- 使用 `window.modelViewer` 访问主应用实例
|
||||||
|
- 各管理器实例可通过modelViewer实例访问
|
||||||
|
- 开启浏览器开发者工具查看Three.js性能面板
|
||||||
|
|
||||||
|
### 性能优化
|
||||||
|
- 大模型文件建议压缩优化
|
||||||
|
- 使用LOD (Level of Detail) 技术
|
||||||
|
- 合理使用材质和纹理
|
||||||
|
- 避免过度的实时计算
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### CORS错误
|
||||||
|
确保通过HTTP服务器访问,而不是直接打开HTML文件
|
||||||
|
|
||||||
|
### 模型加载失败
|
||||||
|
检查模型文件路径和格式,确保.glb文件完整性
|
||||||
|
|
||||||
|
### Three.js版本兼容
|
||||||
|
项目基于Three.js r150+,更新版本时注意API变更
|
||||||
|
|
||||||
|
### 内存泄漏
|
||||||
|
及时清理不需要的几何体、材质和纹理对象
|
||||||
@ -17,6 +17,26 @@ console = Console()
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _display_chapters_recursive(chapters, indent_level=0):
|
||||||
|
"""递归显示章节结构"""
|
||||||
|
for chapter in chapters:
|
||||||
|
indent = " " * indent_level
|
||||||
|
|
||||||
|
# 根据层级设置不同的样式
|
||||||
|
if chapter.level == 1:
|
||||||
|
style = "bold blue"
|
||||||
|
elif chapter.level == 2:
|
||||||
|
style = "green"
|
||||||
|
else: # level 3
|
||||||
|
style = "yellow"
|
||||||
|
|
||||||
|
console.print(f"{indent}{chapter.title}", style=style)
|
||||||
|
|
||||||
|
# 递归显示子章节
|
||||||
|
if chapter.children:
|
||||||
|
_display_chapters_recursive(chapter.children, indent_level + 1)
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
def project():
|
def project():
|
||||||
"""项目管理命令"""
|
"""项目管理命令"""
|
||||||
@ -90,9 +110,7 @@ def parse(scoring_file: str, deviation_file: str | None, template_file: str | No
|
|||||||
# 显示模板章节(如果有)
|
# 显示模板章节(如果有)
|
||||||
if bid_structure.chapters:
|
if bid_structure.chapters:
|
||||||
console.print("\n📚 模板章节:")
|
console.print("\n📚 模板章节:")
|
||||||
for chapter in bid_structure.chapters:
|
_display_chapters_recursive(bid_structure.chapters)
|
||||||
indent = " " * chapter.level
|
|
||||||
console.print(f"{indent}• {chapter.title}")
|
|
||||||
|
|
||||||
# 显示统计信息
|
# 显示统计信息
|
||||||
stats_panel = Panel(
|
stats_panel = Panel(
|
||||||
@ -193,8 +211,7 @@ def smart_parse(word_file: str):
|
|||||||
|
|
||||||
# 显示生成的目录结构
|
# 显示生成的目录结构
|
||||||
console.print("\n📚 生成的目录结构:")
|
console.print("\n📚 生成的目录结构:")
|
||||||
for chapter in bid_structure.chapters:
|
_display_chapters_recursive(bid_structure.chapters)
|
||||||
console.print(f" {chapter.title}")
|
|
||||||
|
|
||||||
# 显示统计信息
|
# 显示统计信息
|
||||||
stats_panel = Panel(
|
stats_panel = Panel(
|
||||||
|
|||||||
@ -56,6 +56,8 @@ class DocumentChapter(BaseModel):
|
|||||||
id: str = Field(..., description="章节ID")
|
id: str = Field(..., description="章节ID")
|
||||||
title: str = Field(..., description="章节标题")
|
title: str = Field(..., description="章节标题")
|
||||||
level: int = Field(..., description="章节层级")
|
level: int = Field(..., description="章节层级")
|
||||||
|
score: float | None = Field(default=None, description="评分值")
|
||||||
|
children: List['DocumentChapter'] = Field(default_factory=list, description="子章节")
|
||||||
template_placeholder: str | None = Field(default=None, description="模板占位符")
|
template_placeholder: str | None = Field(default=None, description="模板占位符")
|
||||||
|
|
||||||
|
|
||||||
@ -297,11 +299,24 @@ class BidParser:
|
|||||||
return criteria
|
return criteria
|
||||||
|
|
||||||
def _extract_table_text(self, table) -> str:
|
def _extract_table_text(self, table) -> str:
|
||||||
"""提取表格内容为文本格式"""
|
"""提取表格内容为文本格式,处理合并单元格"""
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
|
# 获取表格的基本信息
|
||||||
|
max_cols = max(len(row.cells) for row in table.rows) if table.rows else 0
|
||||||
|
|
||||||
for i, row in enumerate(table.rows):
|
for i, row in enumerate(table.rows):
|
||||||
cells = [cell.text.strip() for cell in row.cells]
|
cells = []
|
||||||
|
for j in range(max_cols):
|
||||||
|
if j < len(row.cells):
|
||||||
|
cell_text = row.cells[j].text.strip()
|
||||||
|
# 处理空单元格
|
||||||
|
if not cell_text:
|
||||||
|
cell_text = "[空]"
|
||||||
|
cells.append(cell_text)
|
||||||
|
else:
|
||||||
|
cells.append("[空]")
|
||||||
|
|
||||||
# 使用制表符分隔,便于AI理解
|
# 使用制表符分隔,便于AI理解
|
||||||
line = "\t".join(cells)
|
line = "\t".join(cells)
|
||||||
lines.append(f"行{i+1}: {line}")
|
lines.append(f"行{i+1}: {line}")
|
||||||
@ -312,37 +327,41 @@ class BidParser:
|
|||||||
"""使用AI解析评分表格"""
|
"""使用AI解析评分表格"""
|
||||||
try:
|
try:
|
||||||
prompt = f"""
|
prompt = f"""
|
||||||
请提取表格中的评分项和分值,并智能分类,返回JSON。
|
请从复杂的评分表格中提取评分项和分值,并智能分类,返回JSON。
|
||||||
|
|
||||||
表格内容:
|
表格内容:
|
||||||
{table_text}
|
{table_text}
|
||||||
|
|
||||||
要求:
|
要求:
|
||||||
1. 提取评分项名称和分值
|
1. 仔细分析表格结构,即使有合并单元格也要正确提取
|
||||||
2. 描述字段用简短概括(不超过30字)
|
2. 从"评审内容"、"评分因素"、"评分标准"等列中提取评分项名称
|
||||||
3. 根据评分项内容智能分类,重点区分商务和技术:
|
3. 从"分值"列或评分标准描述中提取具体分值(如3分、5分、40分)
|
||||||
|
4. 忽略总分构成等汇总信息,只提取具体评分项
|
||||||
|
5. 智能分类各评分项:
|
||||||
|
|
||||||
**技术类别:**
|
**技术类别:**
|
||||||
- technical_solution: 技术方案、技术完整性、技术先进性、技术路线
|
- technical_solution: 技术方案、技术条款、技术完整性、技术先进性
|
||||||
- equipment_spec: 设备规格、产品参数、设备可靠性、技术指标
|
- equipment_spec: 设备规格、产品参数、设备可靠性、技术指标
|
||||||
- implementation: 项目实施、施工方案、进度计划、实施能力
|
- implementation: 项目实施、施工方案、进度计划、实施能力
|
||||||
- quality_safety: 质量管理、安全管理、环境管理、质量体系
|
- quality_safety: 质量管理、安全管理、环境管理、质量体系
|
||||||
- after_sales: 售后服务、维保服务、培训服务、技术支持
|
- after_sales: 售后服务、维保服务、培训服务、技术支持、服务部分
|
||||||
- compliance: 技术资质、认证证书、技术合规性
|
- compliance: 技术资质、认证证书、技术合规性、技术条款应答
|
||||||
|
|
||||||
**商务类别:**
|
**商务类别:**
|
||||||
- commercial: 价格评分、报价、商务条件、企业资质、财务状况、业绩、投标保证金、商务合规性
|
- commercial: 价格评分、报价、商务条件、企业资质、财务状况、业绩、商务条款应答、响应文件制作质量、同类项目业绩、商务部分
|
||||||
|
|
||||||
**其他:**
|
示例输入分析:
|
||||||
- other: 无法明确分类的项目
|
- "响应文件制作质量 3分" → 商务类别
|
||||||
|
- "同类项目业绩 5分" → 商务类别
|
||||||
|
- "技术条款应答 2分" → 合规类别
|
||||||
|
- "商务条款应答 2分" → 商务类别
|
||||||
|
|
||||||
格式:
|
格式:
|
||||||
{{
|
{{
|
||||||
"scoring_criteria": [
|
"scoring_criteria": [
|
||||||
{{"item_name": "报价", "max_score": 30, "description": "价格评分标准", "category": "commercial"}},
|
{{"item_name": "响应文件制作质量", "max_score": 3, "description": "文件格式内容要求", "category": "commercial"}},
|
||||||
{{"item_name": "技术方案", "max_score": 40, "description": "技术方案评分", "category": "technical_solution"}},
|
{{"item_name": "同类项目业绩", "max_score": 5, "description": "项目经验证明", "category": "commercial"}},
|
||||||
{{"item_name": "企业资质", "max_score": 10, "description": "企业资质证明", "category": "commercial"}},
|
{{"item_name": "技术条款应答", "max_score": 2, "description": "技术要求符合性", "category": "compliance"}}
|
||||||
{{"item_name": "设备参数", "max_score": 20, "description": "设备技术指标", "category": "equipment_spec"}}
|
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -356,8 +375,21 @@ class BidParser:
|
|||||||
|
|
||||||
# 解析AI响应
|
# 解析AI响应
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
if not response or response.strip() == "":
|
||||||
|
logger.error("AI返回空响应")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 尝试清理响应内容
|
||||||
|
clean_response = response.strip()
|
||||||
|
if clean_response.startswith("```json"):
|
||||||
|
clean_response = clean_response[7:]
|
||||||
|
if clean_response.endswith("```"):
|
||||||
|
clean_response = clean_response[:-3]
|
||||||
|
clean_response = clean_response.strip()
|
||||||
|
|
||||||
# 直接解析JSON,失败就抛出异常
|
# 直接解析JSON,失败就抛出异常
|
||||||
result_data = json.loads(response)
|
result_data = json.loads(clean_response)
|
||||||
|
|
||||||
scoring_data = result_data.get("scoring_criteria", [])
|
scoring_data = result_data.get("scoring_criteria", [])
|
||||||
|
|
||||||
@ -426,10 +458,17 @@ class BidParser:
|
|||||||
{table_text}
|
{table_text}
|
||||||
|
|
||||||
请判断这个表格属于以下哪种类型:
|
请判断这个表格属于以下哪种类型:
|
||||||
1. scoring - 评分表:包含评分项、分值、评分标准等
|
1. scoring - 评分表:包含评分项、分值、评分标准等内容,例如:
|
||||||
|
- 有"分值"、"评分标准"、"得分"等列
|
||||||
|
- 有具体的分值数字(如3分、5分、40分等)
|
||||||
|
- 有"商务部分"、"技术部分"、"服务部分"等分类
|
||||||
|
- 有评审内容和评分因素
|
||||||
|
|
||||||
2. deviation - 偏离表:包含技术要求、响应类型、偏离说明等
|
2. deviation - 偏离表:包含技术要求、响应类型、偏离说明等
|
||||||
3. other - 其他表格:不是评分表也不是偏离表
|
3. other - 其他表格:不是评分表也不是偏离表
|
||||||
|
|
||||||
|
注意:即使表格结构复杂、有合并单元格,只要包含评分标准和分值信息就是评分表。
|
||||||
|
|
||||||
只返回一个单词:scoring 或 deviation 或 other"""
|
只返回一个单词:scoring 或 deviation 或 other"""
|
||||||
|
|
||||||
response = self._call_llm_api(prompt)
|
response = self._call_llm_api(prompt)
|
||||||
@ -684,40 +723,133 @@ class BidParser:
|
|||||||
|
|
||||||
return chapters
|
return chapters
|
||||||
|
|
||||||
def _generate_professional_chapters(self, scoring_criteria: List[ScoringCriteria]) -> List[DocumentChapter]:
|
def _group_scoring_items(self, scoring_criteria: List[ScoringCriteria], category: TechnicalCategory) -> dict[str, List[ScoringCriteria]]:
|
||||||
"""基于评分标准生成专业目录结构"""
|
"""对同一类别下的评分项进行智能分组"""
|
||||||
chapters = []
|
# 过滤出指定类别的评分项
|
||||||
|
category_items = [item for item in scoring_criteria if item.category == category]
|
||||||
|
|
||||||
# 获取涉及的技术类别
|
if not category_items:
|
||||||
categories_used = set()
|
return {}
|
||||||
for criteria in scoring_criteria:
|
|
||||||
categories_used.add(criteria.category.value)
|
groups = {}
|
||||||
|
|
||||||
|
for item in category_items:
|
||||||
|
item_name = item.item_name
|
||||||
|
group_key = None
|
||||||
|
|
||||||
|
# 规则1:识别前缀模式(如"平台要求-xxx")
|
||||||
|
if "-" in item_name:
|
||||||
|
prefix = item_name.split("-")[0].strip()
|
||||||
|
if len(prefix) <= 10: # 前缀不能太长
|
||||||
|
group_key = f"{prefix}要求"
|
||||||
|
|
||||||
|
# 规则2:识别关键词分组
|
||||||
|
if not group_key:
|
||||||
|
keywords_mapping = {
|
||||||
|
"原型": "系统原型设计",
|
||||||
|
"展示": "系统原型设计",
|
||||||
|
"方案": "方案设计",
|
||||||
|
"投标": "方案设计",
|
||||||
|
"人员": "人员配置方案",
|
||||||
|
"配置": "人员配置方案",
|
||||||
|
"测试": "测试质量保障",
|
||||||
|
"工具": "测试质量保障",
|
||||||
|
"质保": "质保服务方案",
|
||||||
|
"售后": "售后服务方案",
|
||||||
|
"服务": "售后服务方案",
|
||||||
|
"企业": "企业资质证明",
|
||||||
|
"实力": "企业资质证明",
|
||||||
|
"认证": "技术认证证书",
|
||||||
|
"证书": "技术认证证书",
|
||||||
|
"适配": "技术认证证书"
|
||||||
|
}
|
||||||
|
|
||||||
|
for keyword, group_name in keywords_mapping.items():
|
||||||
|
if keyword in item_name:
|
||||||
|
group_key = group_name
|
||||||
|
break
|
||||||
|
|
||||||
|
# 规则3:默认分组
|
||||||
|
if not group_key:
|
||||||
|
group_key = "其他要求"
|
||||||
|
|
||||||
|
if group_key not in groups:
|
||||||
|
groups[group_key] = []
|
||||||
|
groups[group_key].append(item)
|
||||||
|
|
||||||
|
return groups
|
||||||
|
|
||||||
|
def _add_sub_chapters(self, parent_chapter: DocumentChapter, groups: dict[str, List[ScoringCriteria]], chapter_num: str) -> None:
|
||||||
|
"""为父章节添加二三级子章节"""
|
||||||
|
if not groups:
|
||||||
|
return
|
||||||
|
|
||||||
|
sub_chapter_index = 1
|
||||||
|
for group_name, scoring_items in groups.items():
|
||||||
|
# 创建二级标题
|
||||||
|
sub_chapter_id = f"{parent_chapter.id}_{sub_chapter_index:02d}"
|
||||||
|
sub_chapter_title = f"{chapter_num}.{sub_chapter_index} {group_name}"
|
||||||
|
|
||||||
|
sub_chapter = DocumentChapter(
|
||||||
|
id=sub_chapter_id,
|
||||||
|
title=sub_chapter_title,
|
||||||
|
level=2,
|
||||||
|
template_placeholder=f"{{{{{sub_chapter_id}_content}}}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 为二级标题添加三级标题(具体评分项)
|
||||||
|
item_index = 1
|
||||||
|
for scoring_item in scoring_items:
|
||||||
|
item_chapter_id = f"{sub_chapter_id}_{item_index:02d}"
|
||||||
|
item_title = f"{chapter_num}.{sub_chapter_index}.{item_index} {scoring_item.item_name}"
|
||||||
|
if scoring_item.max_score > 0:
|
||||||
|
item_title += f" ({scoring_item.max_score}分)"
|
||||||
|
|
||||||
|
item_chapter = DocumentChapter(
|
||||||
|
id=item_chapter_id,
|
||||||
|
title=item_title,
|
||||||
|
level=3,
|
||||||
|
score=scoring_item.max_score,
|
||||||
|
template_placeholder=f"{{{{{item_chapter_id}_content}}}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
sub_chapter.children.append(item_chapter)
|
||||||
|
item_index += 1
|
||||||
|
|
||||||
|
parent_chapter.children.append(sub_chapter)
|
||||||
|
sub_chapter_index += 1
|
||||||
|
|
||||||
|
def _generate_professional_chapters(self, scoring_criteria: List[ScoringCriteria]) -> List[DocumentChapter]:
|
||||||
|
"""基于评分标准生成专业三级目录结构"""
|
||||||
|
chapters = []
|
||||||
|
|
||||||
# 1. 评标索引表(始终包含)
|
# 1. 评标索引表(始终包含)
|
||||||
chapters.append(self._create_standard_chapter("evaluation_index"))
|
chapters.append(self._create_standard_chapter("evaluation_index"))
|
||||||
|
|
||||||
# 2. 合规响应表(如果有偏离项或合规类评分项)
|
# 2. 合规响应表(始终包含)
|
||||||
if any(c.category == TechnicalCategory.COMPLIANCE for c in scoring_criteria):
|
compliance_chapter = self._create_standard_chapter("compliance_response")
|
||||||
chapters.append(self._create_standard_chapter("compliance_response"))
|
# 为合规章节添加二三级标题
|
||||||
else:
|
compliance_groups = self._group_scoring_items(scoring_criteria, TechnicalCategory.COMPLIANCE)
|
||||||
# 即使没有合规类评分项,也添加偏离表章节(招投标标准要求)
|
self._add_sub_chapters(compliance_chapter, compliance_groups, "2")
|
||||||
chapters.append(self._create_standard_chapter("compliance_response"))
|
chapters.append(compliance_chapter)
|
||||||
|
|
||||||
# 3. 根据评分项类别添加相应章节
|
# 3-7. 技术章节
|
||||||
category_order = [
|
technical_chapters = [
|
||||||
"technical_solution",
|
("technical_solution", TechnicalCategory.TECHNICAL_SOLUTION, "3"),
|
||||||
"equipment_spec",
|
("equipment_spec", TechnicalCategory.EQUIPMENT_SPEC, "4"),
|
||||||
"implementation",
|
("implementation", TechnicalCategory.IMPLEMENTATION, "5"),
|
||||||
"quality_system",
|
("quality_system", TechnicalCategory.QUALITY_SAFETY, "6"),
|
||||||
"after_sales"
|
("after_sales", TechnicalCategory.AFTER_SALES, "7")
|
||||||
]
|
]
|
||||||
|
|
||||||
for category_key in category_order:
|
for chapter_key, category, chapter_num in technical_chapters:
|
||||||
if category_key in categories_used or category_key == "technical_solution":
|
chapter = self._create_standard_chapter(chapter_key)
|
||||||
# 技术方案章节始终包含(作为兜底章节)
|
# 为每个技术章节添加二三级标题
|
||||||
chapters.append(self._create_standard_chapter(category_key))
|
category_groups = self._group_scoring_items(scoring_criteria, category)
|
||||||
|
self._add_sub_chapters(chapter, category_groups, chapter_num)
|
||||||
|
chapters.append(chapter)
|
||||||
|
|
||||||
# 4. 验收与绩效考核对应表(标准履约要求,始终包含)
|
# 8. 验收与绩效考核对应表(始终包含)
|
||||||
chapters.append(self._create_standard_chapter("contract_delivery"))
|
chapters.append(self._create_standard_chapter("contract_delivery"))
|
||||||
|
|
||||||
return chapters
|
return chapters
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user