someone-oa/generate_simple_quotation.py
2025-12-11 15:21:16 +08:00

501 lines
20 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()