501 lines
20 KiB
Python
501 lines
20 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
生成简化的OA系统项目报价文档(只包含总人天和最终费用)
|
||
"""
|
||
from docx import Document
|
||
from docx.shared import Pt
|
||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||
from datetime import datetime
|
||
from docx.oxml.ns import qn
|
||
|
||
def set_chinese_font(run, font_name='宋体'):
|
||
"""设置中文字体"""
|
||
run.font.name = font_name
|
||
run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
|
||
|
||
def add_table_with_header(doc, headers, data, style='Light Grid Accent 1'):
|
||
"""创建带表头的表格"""
|
||
table = doc.add_table(rows=1, cols=len(headers))
|
||
table.style = style
|
||
|
||
hdr_cells = table.rows[0].cells
|
||
for i, header in enumerate(headers):
|
||
hdr_cells[i].text = header
|
||
for paragraph in hdr_cells[i].paragraphs:
|
||
for run in paragraph.runs:
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
for row_data in data:
|
||
row_cells = table.add_row().cells
|
||
for i, cell_data in enumerate(row_data):
|
||
row_cells[i].text = str(cell_data)
|
||
for paragraph in row_cells[i].paragraphs:
|
||
for run in paragraph.runs:
|
||
set_chinese_font(run)
|
||
|
||
return table
|
||
|
||
def generate_simple_quotation():
|
||
"""生成简化报价文档"""
|
||
doc = Document()
|
||
|
||
style = doc.styles['Normal']
|
||
font = style.font
|
||
font.name = '宋体'
|
||
font.size = Pt(12)
|
||
|
||
# ========== 文档封面 ==========
|
||
title = doc.add_heading('OA系统开发项目报价书', 0)
|
||
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
|
||
subtitle = doc.add_paragraph()
|
||
subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
run = subtitle.add_run('(产品需求文档 v1.0)')
|
||
run.font.size = Pt(14)
|
||
set_chinese_font(run)
|
||
|
||
for _ in range(5):
|
||
doc.add_paragraph()
|
||
|
||
company_info = doc.add_paragraph()
|
||
company_info.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
run = company_info.add_run('项目报价单位:[您的公司名称]')
|
||
run.font.size = Pt(14)
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_paragraph()
|
||
|
||
date_para = doc.add_paragraph()
|
||
date_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
run = date_para.add_run(f'报价日期:{datetime.now().strftime("%Y年%m月%d日")}')
|
||
run.font.size = Pt(12)
|
||
set_chinese_font(run)
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 一、项目概述 ==========
|
||
doc.add_heading('一、项目概述', 1)
|
||
|
||
doc.add_paragraph('OA系统开发项目,包含项目全生命周期管理功能,支持从商机立项到项目完成、财务结算的全流程管理。系统需支持PC端和移动端,实现项目管理数字化、流程化、可视化管理。')
|
||
|
||
doc.add_paragraph('主要功能模块:')
|
||
modules = [
|
||
'商机(立项)管理模块',
|
||
'项目过程管理模块',
|
||
'财务管理模块',
|
||
'报表管理模块',
|
||
'系统设置模块',
|
||
'移动端应用(iOS和Android)'
|
||
]
|
||
for module in modules:
|
||
p = doc.add_paragraph(module, style='List Bullet')
|
||
set_chinese_font(p.runs[0])
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 二、项目工作量 ==========
|
||
doc.add_heading('二、项目工作量', 1)
|
||
|
||
doc.add_paragraph('基于详细需求文档,项目工作量详细评估如下(人天单价:¥400/天):')
|
||
|
||
doc.add_heading('2.1 需求与设计阶段', 2)
|
||
|
||
design_work = [
|
||
('需求分析与原型设计', 8, '需求调研、业务流程梳理、原型设计、需求文档编写'),
|
||
('数据库设计', 4, '数据库表结构设计、索引优化、数据字典编写'),
|
||
('接口设计', 4, 'RESTful API设计、接口文档编写(Swagger)'),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作内容', '工作量(人天)', '详细说明'], design_work)
|
||
|
||
design_total = sum(item[1] for item in design_work)
|
||
doc.add_paragraph()
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(f'需求与设计阶段小计:{design_total}人天')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_heading('2.2 后端开发阶段', 2)
|
||
|
||
backend_work = [
|
||
('用户权限模块', 8, '用户管理、角色管理、权限控制、登录认证'),
|
||
('组织架构模块', 4, '部门管理、人员管理、组织树结构'),
|
||
('商机管理模块', 10, '立项申请、审核流程、项目查询、状态管理'),
|
||
('项目过程管理模块', 13, '项目启动、成果管理、进度查询、审核流程'),
|
||
('财务管理模块', 8, '开票管理、回款管理、请款管理'),
|
||
('报表管理模块', 13, '8种报表开发、数据统计、Excel/PDF导出'),
|
||
('消息通知模块', 8, '站内消息、邮件、短信、推送通知'),
|
||
('附件管理模块', 5, '文件上传、下载、预览、存储管理'),
|
||
('审核流程引擎', 9, '可配置审核流程、审核节点管理'),
|
||
('产值计算引擎', 6, '产值计算公式、费用计算'),
|
||
('系统设置模块', 4, '参数配置、流程配置'),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作内容', '工作量(人天)', '详细说明'], backend_work)
|
||
|
||
backend_total = sum(item[1] for item in backend_work)
|
||
doc.add_paragraph()
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(f'后端开发阶段小计:{backend_total}人天')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_heading('2.3 PC前端开发阶段', 2)
|
||
|
||
frontend_work = [
|
||
('基础框架搭建', 6, 'Vue3项目搭建、路由、状态管理、公共组件'),
|
||
('用户权限前端', 5, '登录页面、权限控制、菜单管理'),
|
||
('商机管理前端', 8, '立项申请页面、审核页面、项目查询页面'),
|
||
('项目过程管理前端', 10, '启动申请、成果提交、进度查询等页面'),
|
||
('财务管理前端', 6, '开票申请、回款管理、请款管理页面'),
|
||
('报表管理前端', 9, '8种报表页面、图表展示、数据导出'),
|
||
('系统设置前端', 6, '组织架构、账号管理、权限配置页面'),
|
||
('通用组件开发', 5, '表格、表单、上传、审核流程组件等'),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作内容', '工作量(人天)', '详细说明'], frontend_work)
|
||
|
||
frontend_total = sum(item[1] for item in frontend_work)
|
||
doc.add_paragraph()
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(f'PC前端开发阶段小计:{frontend_total}人天')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_heading('2.4 移动端开发阶段', 2)
|
||
|
||
mobile_work = [
|
||
('移动端框架搭建', 4, '移动端项目搭建、路由、API封装'),
|
||
('移动端基础功能', 5, '登录、首页、消息通知、个人信息'),
|
||
('移动端待办功能', 6, '待办列表、审核操作、消息推送'),
|
||
('移动端查询功能', 5, '项目查询、进度查询、简单报表'),
|
||
('移动端成果提交', 4, '成果提交、附件上传(小文件)'),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作内容', '工作量(人天)', '详细说明'], mobile_work)
|
||
|
||
mobile_total = sum(item[1] for item in mobile_work)
|
||
doc.add_paragraph()
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(f'移动端开发阶段小计:{mobile_total}人天')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_heading('2.5 测试阶段', 2)
|
||
|
||
test_work = [
|
||
('单元测试', 8, '后端单元测试、前端单元测试'),
|
||
('功能测试', 10, '各模块功能测试、业务流程测试'),
|
||
('性能测试', 4, '性能压力测试、并发测试'),
|
||
('安全测试', 4, '安全漏洞扫描、SQL注入测试等'),
|
||
('兼容性测试', 4, '浏览器兼容、移动端兼容测试'),
|
||
('用户验收测试', 5, 'UAT测试、bug修复'),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作内容', '工作量(人天)', '详细说明'], test_work)
|
||
|
||
test_total = sum(item[1] for item in test_work)
|
||
doc.add_paragraph()
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(f'测试阶段小计:{test_total}人天')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_heading('2.6 部署与文档阶段', 2)
|
||
|
||
deploy_work = [
|
||
('系统部署', 3, '环境搭建、系统部署、数据库初始化'),
|
||
('数据迁移', 3, '历史数据迁移(如有)'),
|
||
('用户手册编写', 4, '用户操作手册、管理员手册'),
|
||
('技术文档编写', 3, '接口文档、数据库文档、部署文档'),
|
||
('用户培训', 3, '培训材料准备、培训实施(2次)'),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作内容', '工作量(人天)', '详细说明'], deploy_work)
|
||
|
||
deploy_total = sum(item[1] for item in deploy_work)
|
||
doc.add_paragraph()
|
||
p = doc.add_paragraph()
|
||
run = p.add_run(f'部署与文档阶段小计:{deploy_total}人天')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
doc.add_page_break()
|
||
|
||
doc.add_heading('2.7 工作量汇总', 2)
|
||
|
||
summary_work = [
|
||
('需求与设计阶段', design_total, ''),
|
||
('后端开发阶段', backend_total, ''),
|
||
('PC前端开发阶段', frontend_total, ''),
|
||
('移动端开发阶段', mobile_total, ''),
|
||
('测试阶段', test_total, ''),
|
||
('部署与文档阶段', deploy_total, ''),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['工作阶段', '工作量(人天)', '备注'], summary_work)
|
||
|
||
doc.add_paragraph()
|
||
|
||
# 总工作量
|
||
total_days = design_total + backend_total + frontend_total + mobile_total + test_total + deploy_total
|
||
p = doc.add_paragraph()
|
||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
run = p.add_run(f'项目总工作量:{total_days}人天')
|
||
run.bold = True
|
||
run.font.size = Pt(18)
|
||
set_chinese_font(run)
|
||
|
||
doc.add_paragraph()
|
||
doc.add_paragraph('说明:以上工作量基于详细需求文档评估,包含需求、设计、开发、测试、部署、文档等全部工作内容。')
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 三、项目周期 ==========
|
||
doc.add_heading('三、项目周期', 1)
|
||
|
||
doc.add_paragraph(f'项目预计总周期:9周(约2.25个月)')
|
||
|
||
doc.add_paragraph('项目阶段划分:')
|
||
phases = [
|
||
('需求分析与设计', '1周', '需求调研、数据库设计、接口设计'),
|
||
('系统开发', '4周', '后端开发、PC前端开发、移动端开发(并行)'),
|
||
('系统测试', '2周', '功能测试、性能测试、安全测试、验收测试'),
|
||
('部署上线', '1周', '环境搭建、系统部署、试运行'),
|
||
('培训交付', '1周', '文档编写、用户培训、项目验收')
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['项目阶段', '周期', '主要工作'], phases)
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 四、项目费用 ==========
|
||
doc.add_heading('四、项目费用', 1)
|
||
|
||
doc.add_paragraph('项目费用说明:以下费用包含所有开发、测试、部署、培训、质保期维护等费用。')
|
||
|
||
doc.add_paragraph()
|
||
|
||
# 费用汇总(按400元/人天计算)
|
||
# 总工作量:240人天
|
||
# 人力成本:240人天 × 400元/天 = 96,000元
|
||
human_cost = 240 * 400
|
||
other_cost = 15000 # 其他成本
|
||
total_cost = human_cost + other_cost
|
||
profit = int(total_cost * 0.15) # 利润15%
|
||
|
||
cost_summary = [
|
||
('开发费用', f'¥{human_cost:,}', f'240人天 × ¥400/天(包含需求、设计、开发、测试、部署等所有费用)'),
|
||
('其他费用', f'¥{other_cost:,}', '服务器、第三方服务、差旅等费用'),
|
||
('成本合计', f'¥{total_cost:,}', ''),
|
||
('利润(15%)', f'¥{profit:,}', ''),
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['费用项目', '金额', '说明'], cost_summary)
|
||
|
||
doc.add_paragraph()
|
||
|
||
# 最终价格
|
||
final_price = total_cost + profit
|
||
p = doc.add_paragraph()
|
||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
run = p.add_run(f'项目总价(含税):¥{final_price:,}')
|
||
run.bold = True
|
||
run.font.size = Pt(20)
|
||
set_chinese_font(run)
|
||
|
||
doc.add_paragraph()
|
||
doc.add_heading('4.1 费用计算明细', 2)
|
||
|
||
calc_data = [
|
||
('项目总工作量', f'{total_days}人天'),
|
||
('人天单价', '¥400/天'),
|
||
('人力成本', f'¥{human_cost:,}({total_days}人天 × ¥400/天)'),
|
||
('其他成本', f'¥{other_cost:,}(服务器、第三方服务、差旅等)'),
|
||
('成本合计', f'¥{total_cost:,}'),
|
||
('利润(15%)', f'¥{profit:,}'),
|
||
('项目总价(含税)', f'¥{final_price:,}'),
|
||
]
|
||
|
||
calc_table = add_table_with_header(doc, ['费用项目', '金额/说明'], calc_data)
|
||
|
||
doc.add_paragraph()
|
||
doc.add_heading('4.2 费用说明', 2)
|
||
|
||
doc.add_paragraph('费用包含内容:')
|
||
fee_includes = [
|
||
'系统开发:包含需求分析、设计、开发、测试、部署等全部工作',
|
||
'质保服务:12个月质保期内的bug修复和技术支持(免费)',
|
||
'用户培训:不少于2次集中培训,包含培训材料和操作视频',
|
||
'项目文档:用户手册、管理员手册、技术文档、接口文档等',
|
||
'系统部署:生产环境部署、数据库初始化、系统配置等'
|
||
]
|
||
for item in fee_includes:
|
||
p = doc.add_paragraph(item, style='List Bullet')
|
||
set_chinese_font(p.runs[0])
|
||
|
||
doc.add_paragraph()
|
||
doc.add_paragraph('其他说明:')
|
||
other_notes = [
|
||
'以上费用为含税价格,发票类型为增值税专用发票',
|
||
'人天单价按¥400/天计算,基于240人天总工作量评估',
|
||
'其他费用包含服务器、第三方服务(短信、邮件等)、差旅等',
|
||
'如需求发生重大变更,费用和周期需重新评估'
|
||
]
|
||
for note in other_notes:
|
||
p = doc.add_paragraph(note, style='List Bullet')
|
||
set_chinese_font(p.runs[0])
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 五、付款方式 ==========
|
||
doc.add_heading('五、付款方式', 1)
|
||
|
||
doc.add_paragraph('付款方式说明:项目采用分阶段付款方式,具体付款节点和比例如下(可协商调整):')
|
||
|
||
# 计算付款金额
|
||
payment_amounts = [
|
||
int(final_price * 0.3), # 首付款30%
|
||
int(final_price * 0.2), # 进度款1 20%
|
||
int(final_price * 0.3), # 进度款2 30%
|
||
int(final_price * 0.15), # 验收款15%
|
||
int(final_price * 0.05) # 质保金5%
|
||
]
|
||
|
||
payment_terms = [
|
||
('首付款', '合同签订后3个工作日内', '30%', f'¥{payment_amounts[0]:,}'),
|
||
('进度款1', '原型设计确认后', '20%', f'¥{payment_amounts[1]:,}'),
|
||
('进度款2', '开发完成并提交测试后', '30%', f'¥{payment_amounts[2]:,}'),
|
||
('验收款', '项目验收通过后', '15%', f'¥{payment_amounts[3]:,}'),
|
||
('质保金', '质保期结束后', '5%', f'¥{payment_amounts[4]:,}')
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['付款节点', '付款条件', '付款比例', '金额'], payment_terms)
|
||
|
||
doc.add_paragraph()
|
||
doc.add_paragraph('付款说明:')
|
||
payment_notes = [
|
||
'首付款在合同签订后3个工作日内支付,项目正式启动',
|
||
'进度款在相应里程碑达成后支付',
|
||
'验收款在项目验收通过后支付',
|
||
'质保金在12个月质保期结束后支付',
|
||
'所有付款均需提供相应发票'
|
||
]
|
||
for note in payment_notes:
|
||
p = doc.add_paragraph(note, style='List Bullet')
|
||
set_chinese_font(p.runs[0])
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 六、交付内容 ==========
|
||
doc.add_heading('六、交付内容', 1)
|
||
|
||
doc.add_paragraph('项目交付包含以下内容:')
|
||
|
||
deliverables = [
|
||
('源代码', '系统源代码(前端、后端、移动端),包含完整注释'),
|
||
('部署包', '系统部署包和部署文档,支持一键部署'),
|
||
('数据库脚本', '数据库初始化脚本和升级脚本'),
|
||
('接口文档', '完整的RESTful API接口文档(Swagger格式)'),
|
||
('用户手册', '用户操作手册(PC端、移动端),包含操作截图'),
|
||
('管理员手册', '系统管理员手册,包含配置和维护说明'),
|
||
('技术文档', '技术文档(数据库设计、系统架构、技术选型)'),
|
||
('测试报告', '功能测试、性能测试、安全测试报告'),
|
||
('培训材料', '培训PPT、操作视频、FAQ文档')
|
||
]
|
||
|
||
deliverable_table = add_table_with_header(doc, ['交付物', '说明'], deliverables)
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 七、质保服务 ==========
|
||
doc.add_heading('七、质保服务', 1)
|
||
|
||
doc.add_paragraph('质保期:自项目验收通过之日起12个月。')
|
||
|
||
doc.add_heading('7.1 质保期内服务内容', 2)
|
||
|
||
warranty_services = [
|
||
('bug修复', '免费修复系统运行中发现的bug和缺陷'),
|
||
('技术支持', '免费技术支持(工作日工作时间:9:00-18:00)'),
|
||
('系统优化', '免费系统优化(性能优化、安全加固等)'),
|
||
('紧急支持', '7×24小时紧急技术支持(系统故障)'),
|
||
('版本升级', '免费提供系统版本升级(功能增强需另行协商)')
|
||
]
|
||
|
||
warranty_table = add_table_with_header(doc, ['服务项目', '服务内容'], warranty_services)
|
||
|
||
doc.add_heading('7.2 质保期外服务', 2)
|
||
doc.add_paragraph('质保期结束后,如需继续技术支持,可签订年度维护合同,费用另行协商。')
|
||
|
||
doc.add_page_break()
|
||
|
||
# ========== 八、联系方式 ==========
|
||
doc.add_heading('八、联系方式', 1)
|
||
|
||
contact_info = [
|
||
('项目负责人', '[姓名]', '[电话]', '[邮箱]'),
|
||
('技术负责人', '[姓名]', '[电话]', '[邮箱]'),
|
||
('商务联系人', '[姓名]', '[电话]', '[邮箱]'),
|
||
('公司地址', '[详细地址]', '', '')
|
||
]
|
||
|
||
table = add_table_with_header(doc, ['联系人', '姓名', '电话', '邮箱'], contact_info)
|
||
|
||
# ========== 结尾 ==========
|
||
doc.add_page_break()
|
||
|
||
doc.add_paragraph()
|
||
doc.add_paragraph()
|
||
|
||
end_para = doc.add_paragraph()
|
||
end_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT
|
||
run = end_para.add_run('[您的公司名称]')
|
||
run.bold = True
|
||
set_chinese_font(run)
|
||
|
||
date_para = doc.add_paragraph()
|
||
date_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT
|
||
run = date_para.add_run(datetime.now().strftime("%Y年%m月%d日"))
|
||
set_chinese_font(run)
|
||
|
||
return doc
|
||
|
||
def main():
|
||
print("正在生成简化报价文档...")
|
||
doc = generate_simple_quotation()
|
||
|
||
import os
|
||
from datetime import datetime
|
||
output_file = "项目报价文档.docx"
|
||
if os.path.exists(output_file):
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
output_file = f"项目报价文档_{timestamp}.docx"
|
||
doc.save(output_file)
|
||
|
||
print(f"✓ 报价文档生成成功!")
|
||
print(f" 文件路径: {output_file}")
|
||
# 计算总工作量
|
||
total_days_no_ui = 240
|
||
|
||
# 按400元/人天计算费用
|
||
human_cost = 240 * 400
|
||
other_cost = 15000
|
||
total_cost = human_cost + other_cost
|
||
profit = int(total_cost * 0.15)
|
||
final_price = total_cost + profit
|
||
|
||
print(f"\n报价摘要:")
|
||
print(f" - 项目总工作量: {total_days_no_ui}人天(不含UI设计)")
|
||
print(f" - 人天单价: ¥400/天")
|
||
print(f" - 项目周期: 9周(约2.25个月)")
|
||
print(f" - 项目总价: ¥{final_price:,}(含税,不含UI设计)")
|
||
print(f"\n注意:请填写文档中标注为[XXX]的占位符内容。")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|