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