322 lines
19 KiB
Python
322 lines
19 KiB
Python
# 修改人:Ld 修改时间:2026-08-03 14:07:13; 生成排产优化方案 Word 文档。
|
||
from docx import Document
|
||
from docx.enum.section import WD_SECTION
|
||
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
|
||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||
from docx.oxml import OxmlElement
|
||
from docx.oxml.ns import qn
|
||
from docx.shared import Inches, Pt, RGBColor
|
||
|
||
|
||
OUTPUT = r"D:\景耀\JY1.0\docs\排产优化方案.docx"
|
||
MOD_TIME = "2026-08-03 14:07:13"
|
||
|
||
|
||
def set_run_font(run, size=11, bold=False, color=None, name="Calibri"):
|
||
run.font.name = name
|
||
run._element.rPr.rFonts.set(qn("w:ascii"), name)
|
||
run._element.rPr.rFonts.set(qn("w:hAnsi"), name)
|
||
run._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
|
||
run.font.size = Pt(size)
|
||
run.bold = bold
|
||
if color:
|
||
run.font.color.rgb = RGBColor.from_string(color)
|
||
|
||
|
||
def set_para_format(paragraph, before=0, after=6, line=1.10):
|
||
paragraph.paragraph_format.space_before = Pt(before)
|
||
paragraph.paragraph_format.space_after = Pt(after)
|
||
paragraph.paragraph_format.line_spacing = line
|
||
|
||
|
||
def add_heading(doc, text, level=1):
|
||
p = doc.add_paragraph()
|
||
set_para_format(p, before=16 if level == 1 else 10, after=8 if level == 1 else 5)
|
||
r = p.add_run(text)
|
||
if level == 1:
|
||
set_run_font(r, size=16, bold=True, color="2E74B5")
|
||
else:
|
||
set_run_font(r, size=13, bold=True, color="2E74B5")
|
||
return p
|
||
|
||
|
||
def add_para(doc, text, bold_prefix=None):
|
||
p = doc.add_paragraph()
|
||
set_para_format(p)
|
||
if bold_prefix and text.startswith(bold_prefix):
|
||
r1 = p.add_run(bold_prefix)
|
||
set_run_font(r1, bold=True)
|
||
r2 = p.add_run(text[len(bold_prefix):])
|
||
set_run_font(r2)
|
||
else:
|
||
r = p.add_run(text)
|
||
set_run_font(r)
|
||
return p
|
||
|
||
|
||
def add_bullet(doc, text):
|
||
p = doc.add_paragraph(style="List Bullet")
|
||
set_para_format(p, after=4, line=1.167)
|
||
r = p.add_run(text)
|
||
set_run_font(r)
|
||
return p
|
||
|
||
|
||
def add_number(doc, text):
|
||
p = doc.add_paragraph(style="List Number")
|
||
set_para_format(p, after=4, line=1.167)
|
||
r = p.add_run(text)
|
||
set_run_font(r)
|
||
return p
|
||
|
||
|
||
def shade_cell(cell, fill):
|
||
tc_pr = cell._tc.get_or_add_tcPr()
|
||
shd = OxmlElement("w:shd")
|
||
shd.set(qn("w:fill"), fill)
|
||
tc_pr.append(shd)
|
||
|
||
|
||
def set_cell_text(cell, text, bold=False, align=WD_ALIGN_PARAGRAPH.LEFT):
|
||
cell.text = ""
|
||
p = cell.paragraphs[0]
|
||
p.alignment = align
|
||
set_para_format(p, after=0, line=1.10)
|
||
r = p.add_run(text)
|
||
set_run_font(r, size=10.5, bold=bold)
|
||
cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
|
||
|
||
|
||
def add_table(doc, headers, rows, widths):
|
||
table = doc.add_table(rows=1, cols=len(headers))
|
||
table.alignment = WD_TABLE_ALIGNMENT.CENTER
|
||
table.style = "Table Grid"
|
||
for i, header in enumerate(headers):
|
||
set_cell_text(table.rows[0].cells[i], header, bold=True, align=WD_ALIGN_PARAGRAPH.CENTER)
|
||
shade_cell(table.rows[0].cells[i], "F2F4F7")
|
||
table.rows[0].cells[i].width = Inches(widths[i])
|
||
for row in rows:
|
||
cells = table.add_row().cells
|
||
for i, value in enumerate(row):
|
||
set_cell_text(cells[i], str(value), align=WD_ALIGN_PARAGRAPH.LEFT if i > 0 else WD_ALIGN_PARAGRAPH.CENTER)
|
||
cells[i].width = Inches(widths[i])
|
||
doc.add_paragraph()
|
||
return table
|
||
|
||
|
||
def add_callout(doc, title, body):
|
||
table = doc.add_table(rows=1, cols=1)
|
||
table.alignment = WD_TABLE_ALIGNMENT.CENTER
|
||
table.style = "Table Grid"
|
||
cell = table.rows[0].cells[0]
|
||
shade_cell(cell, "F4F6F9")
|
||
p = cell.paragraphs[0]
|
||
set_para_format(p, after=3)
|
||
r = p.add_run(title)
|
||
set_run_font(r, size=11, bold=True, color="1F4D78")
|
||
p2 = cell.add_paragraph()
|
||
set_para_format(p2, after=0)
|
||
r2 = p2.add_run(body)
|
||
set_run_font(r2, size=10.5)
|
||
doc.add_paragraph()
|
||
|
||
|
||
def main():
|
||
doc = Document()
|
||
section = doc.sections[0]
|
||
section.top_margin = Inches(1)
|
||
section.bottom_margin = Inches(1)
|
||
section.left_margin = Inches(1)
|
||
section.right_margin = Inches(1)
|
||
section.header_distance = Inches(0.492)
|
||
section.footer_distance = Inches(0.492)
|
||
|
||
styles = doc.styles
|
||
normal = styles["Normal"]
|
||
normal.font.name = "Calibri"
|
||
normal._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
|
||
normal.font.size = Pt(11)
|
||
normal.paragraph_format.space_after = Pt(6)
|
||
normal.paragraph_format.line_spacing = 1.10
|
||
|
||
header = section.header.paragraphs[0]
|
||
header.alignment = WD_ALIGN_PARAGRAPH.RIGHT
|
||
set_para_format(header, after=0)
|
||
rh = header.add_run("景耀 JY1.0 MES | 排产优化方案")
|
||
set_run_font(rh, size=9, color="555555")
|
||
|
||
footer = section.footer.paragraphs[0]
|
||
footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
rf = footer.add_run("内部方案讨论稿")
|
||
set_run_font(rf, size=9, color="555555")
|
||
|
||
title = doc.add_paragraph()
|
||
set_para_format(title, before=10, after=4)
|
||
tr = title.add_run("排产优化方案")
|
||
set_run_font(tr, size=24, bold=True, color="0B2545")
|
||
|
||
subtitle = doc.add_paragraph()
|
||
set_para_format(subtitle, after=14)
|
||
sr = subtitle.add_run("结合 JY1.0 现有销售合同、补货、生产计划、工序派工与设备任务链路")
|
||
set_run_font(sr, size=12, color="555555")
|
||
|
||
meta = [
|
||
["适用系统", "景耀 JY1.0 MES 前端(Vue 2 + Element UI)及 ASP.NET .ashx 后端"],
|
||
["数据库范围", "测试库 ERPTOOL_JY_20250826Back;正式库 ERPTOOL_JY 上线前同步评审"],
|
||
["方案版本", "V1.0"],
|
||
["生成时间", MOD_TIME],
|
||
]
|
||
add_table(doc, ["项目", "说明"], meta, [1.5, 5.0])
|
||
|
||
add_callout(
|
||
doc,
|
||
"核心结论",
|
||
"建议采用“两步走”:第一阶段先做订单补货可溯源、当前工序高亮、机台任务看板三项可视化闭环;第二阶段在数据稳定后接入有限产能、交期、设备状态、工序前后置约束的自动排产建议。这样能最大限度复用现有页面和 MESCommonBase.ashx 通信模式,避免一次性重构带来的风险。",
|
||
)
|
||
|
||
add_heading(doc, "一、现有系统依据")
|
||
add_para(doc, "本次方案基于代码结构和现有业务链路梳理,重点参考以下模块:")
|
||
for item in [
|
||
"仓储补货:src/views/WarehouseManagement/Replenishment/index.vue,已具备报缺补货、外购/自制补货中间表、提交补货、补货期限、补货图片、打回通知等能力。",
|
||
"销售订单:src/views/SalesManagement/OrderInquiry/index.vue 与 OrderRelease/index.vue,已具备订单编号、合同类型、补货明细查询/修改、订单投产、订单分配等能力。",
|
||
"销售合同:src/views/SalesManagement/SalesContractNew/index.vue 与 ContractSearchNew/index.vue,已具备合同编号、项目流水号、客户、合同状态和资料留存等合同主数据能力。",
|
||
"生产计划:src/views/SeikoWorkshop/ProductionPlan/index.vue,已具备月度计划、状态、完成率、OP010-OP110 工序列和可视化看板雏形。",
|
||
"生产任务查询与追溯:src/views/SeikoWorkshop/ProductionTaskQuery/index.vue,已具备任务状态、派工、零件追溯、工序明细、加工设备和工序状态变色能力。",
|
||
"生产执行/派工:src/views/SeikoWorkshop/ProductionExecution/index.vue,已具备设备查询、工序信息查询、工序编辑及派工、上移/下移/插入/删除工序、工艺保存派工等能力。",
|
||
"设备监控:src/views/SeikoWorkshop/EquipmentMonitoringNew/index.vue 与 ManufacturingCenter/EquipmentMonitoringNew/index.vue,已具备设备状态展示和设备状态分布图基础。",
|
||
]:
|
||
add_bullet(doc, item)
|
||
|
||
add_heading(doc, "二、目标与边界")
|
||
add_para(doc, "本方案优先解决“计划看得见、任务找得到、来源追得回”的排产基础问题,再逐步进入算法优化。")
|
||
add_table(
|
||
doc,
|
||
["目标", "说明", "优先级"],
|
||
[
|
||
["补货订单可溯源", "创建补货订单时必须关联销售合同或销售订单,后续可从补货单反查合同、客户、订单、零件、需求来源。", "P0"],
|
||
["当前工序凸显", "生产计划和任务查询中对正在加工/待处理的当前工序做高亮、标签和进度提示,减少人工查找。", "P0"],
|
||
["机台任务显示", "按设备/工位展示当前任务、下一任务、排队任务、预计开完工、异常状态,为排产调整提供现场视角。", "P1"],
|
||
["排产算法建议", "在数据字段稳定后,按交期、工序顺序、设备能力、在制数量、设备状态给出推荐排产。", "P2"],
|
||
],
|
||
[1.25, 4.2, 1.05],
|
||
)
|
||
|
||
add_heading(doc, "三、方案一:补货订单关联销售合同")
|
||
add_para(doc, "现状:补货页面已能按物料选择补货并提交,但补货提交参数当前主要围绕“是否外购、操作者、补货期限、订单备注”;需求明细弹窗已能展示订单编号、需求量、客户。建议在补货创建时把合同/订单来源显式固化。")
|
||
add_number(doc, "在补货单提交弹窗中增加“关联销售合同”选择框,支持合同编号、客户、订单编号模糊查询。")
|
||
add_number(doc, "选择合同后,联动显示该合同下未完成订单;如用户从需求量明细进入,可自动带入订单编号和合同编号。")
|
||
add_number(doc, "补货中间表增加合同与订单字段,选入物料时即记录来源;提交生成补货单时把来源写入补货单主表和明细表。")
|
||
add_number(doc, "补货查询、新补货查询、销售订单补货明细中增加合同编号、客户名称、来源订单编号列,并提供跳转到合同查询/订单查询的入口。")
|
||
add_table(
|
||
doc,
|
||
["位置", "建议字段/控件", "处理逻辑"],
|
||
[
|
||
["补货创建弹窗", "关联销售合同、来源订单编号、客户名称", "提交前必填;若为安全库存补货可选择“库存备货”,但需填写备货原因。"],
|
||
["补货中间表", "项目流水号、合同编号、订单流水号、订单编号、来源类型", "选入物料时写入,选出时同步清理。"],
|
||
["补货单主表/明细表", "补货单号、合同编号、订单编号、客户名称、补货原因", "生成正式补货单后用于追溯、看板统计和报表导出。"],
|
||
["订单查询", "补货明细关联合同", "现有“订单信息_补货明细_查询/修改”扩展返回字段。"],
|
||
],
|
||
[1.35, 2.0, 3.15],
|
||
)
|
||
|
||
add_heading(doc, "四、方案二:生产计划当前工序高亮")
|
||
add_para(doc, "现状:生产计划已有 OP010-OP110 横向工序列,生产任务查询的工序明细已有 tableRowClassName1 变色逻辑,完成工序会显示为蓝色背景。建议扩展为“已完成、正在进行、待开始、异常/超期”四类视觉状态。")
|
||
add_table(
|
||
doc,
|
||
["状态", "判断规则", "前端表现"],
|
||
[
|
||
["已完成", "工序状态大于完成阈值、存在加工完成时间或完成状态=1", "浅蓝底 + 完成标签"],
|
||
["正在进行", "存在开始加工时间且无完成时间;或工序状态=加工中", "绿色高亮边框/底色 + “当前”标签"],
|
||
["待开始", "前序已完成、本工序未开始", "淡黄底 + “待加工”标签"],
|
||
["异常/超期", "超过精工期限、设备停机、暂停时间过长、质检不良待处理", "红色文字/标签 + 置顶或筛选项"],
|
||
],
|
||
[1.2, 3.2, 2.1],
|
||
)
|
||
add_para(doc, "前端建议:在 ProductionPlan 的 OP 列中增加 scoped-slot,根据后端返回的“当前工序顺序/当前工序状态/当前设备”或前端解析后的状态决定 class;在 ProductionTaskQuery 的工序追溯弹窗中把“当前工序”与“已完成工序”区分开。")
|
||
add_para(doc, "后端建议:生产计划查询过程返回 当前工序顺序、当前工序名称、当前工序状态、当前设备、当前操作者、计划开始、计划完成、实际开始、实际完成、是否超期。前端只负责展示,不在页面内重复推导复杂状态。")
|
||
|
||
add_heading(doc, "五、方案三:机台生产任务显示")
|
||
add_para(doc, "现状:生产执行已有设备下拉和工序派工,设备监控已有设备状态分布图,但缺少按机台汇总的“当前正在做什么、后面排了什么”。建议新增“机台任务看板”,可挂在精工车间或设备监控模块下。")
|
||
add_table(
|
||
doc,
|
||
["看板区块", "显示内容", "数据来源建议"],
|
||
[
|
||
["机台卡片", "设备名称/工位号、设备状态、当前订单、零件、图号、当前工序、操作者、已完成/计划数量", "基础数据_设备工位点检表 + 车间生产管理_零件工序_视图 + 完成过程情况"],
|
||
["当前任务", "正在加工任务、开始时间、已用时、预计剩余、是否超期", "工序完成过程情况、工序状态、设备状态"],
|
||
["排队任务", "下一道/后续任务,按交期、优先级、工序顺序排序", "派工表/工艺计划表/生产计划查询过程"],
|
||
["异常提示", "停机、暂停、质检不良、缺料、未派设备、超期", "设备状态、质检、仓储需求、任务状态"],
|
||
["操作入口", "跳转生产任务查询、工序追溯、生产执行派工", "保持现有路由跳转方式"],
|
||
],
|
||
[1.25, 2.75, 2.5],
|
||
)
|
||
add_para(doc, "第一版建议只做展示和筛选,不直接在看板上拖拽改排产;待现场认可数据准确性后,再开放“调整设备/调整顺序/插单”的受控操作。")
|
||
|
||
add_heading(doc, "六、数据库与接口改造建议")
|
||
add_table(
|
||
doc,
|
||
["类型", "名称建议", "用途"],
|
||
[
|
||
["查询", "仓储管理_补货关联合同_查询数据", "按合同编号、客户、订单编号查询可关联的销售合同/订单。"],
|
||
["编辑", "报缺补货_选入_带来源", "在选入补货物料时同步写入项目流水号、合同编号、订单流水号、订单编号。"],
|
||
["编辑", "报缺补货_提交_带来源", "提交补货单时校验合同/订单来源并写入正式单据。"],
|
||
["查询", "车间生产管理_生产计划_查询数据", "扩展返回当前工序、当前设备、工序状态码、计划/实际时间等字段。"],
|
||
["查询", "精工车间_机台任务看板_查询数据", "按设备/工位汇总当前任务和排队任务。"],
|
||
],
|
||
[1.1, 2.4, 3.0],
|
||
)
|
||
add_para(doc, "所有接口继续走 MESCommonBase.ashx,前端仍使用 this.CreateData 和 this.ExecDatabase;参数仍按 key=value 字符串规则由全局方法生成,避免新增 Axios 封装。")
|
||
|
||
add_heading(doc, "七、前端改造建议")
|
||
add_bullet(doc, "WarehouseManagement/Replenishment:提交弹窗增加合同选择、来源订单选择、备货原因;表格右侧补货单增加合同编号/订单编号隐藏列或 tooltip。")
|
||
add_bullet(doc, "WarehouseManagement/NewReplenishmentQuery:增加合同编号、订单编号、客户名称列和筛选条件;补货单号点击可查看来源。")
|
||
add_bullet(doc, "SalesManagement/OrderInquiry:补货明细弹窗增加合同关联和修改记录展示,补货订单可反跳补货查询。")
|
||
add_bullet(doc, "SeikoWorkshop/ProductionPlan:OP 列改为状态单元格,增加当前工序高亮;看板图表增加按设备、按当前工序、按超期统计。")
|
||
add_bullet(doc, "SeikoWorkshop/ProductionTaskQuery:工序追溯弹窗区分当前工序、已完成工序、待开始工序、异常工序。")
|
||
add_bullet(doc, "SeikoWorkshop 或 DeviceManagement:新增机台任务看板页面,沿用 app-container > el-card > 搜索栏 + 表格/卡片布局。")
|
||
|
||
add_heading(doc, "八、实施阶段")
|
||
add_table(
|
||
doc,
|
||
["阶段", "范围", "交付物", "建议周期"],
|
||
[
|
||
["阶段1", "补货订单关联合同/订单;补货查询追溯字段", "数据库字段、接口、补货页面、查询页面", "2-4天"],
|
||
["阶段2", "生产计划当前工序高亮;任务查询工序状态优化", "生产计划 OP 状态单元格、工序追溯弹窗优化", "2-3天"],
|
||
["阶段3", "机台任务看板", "设备筛选、当前任务、排队任务、异常提示、跳转入口", "4-6天"],
|
||
["阶段4", "排产算法建议", "规则配置、推荐顺序、人工确认、调整记录", "视规则复杂度评估"],
|
||
],
|
||
[1.0, 2.35, 2.2, 0.95],
|
||
)
|
||
|
||
add_heading(doc, "九、验收标准")
|
||
for item in [
|
||
"创建补货订单时,除库存备货场景外,必须能看到并保存销售合同/订单来源。",
|
||
"从补货查询能反查到合同编号、客户、订单编号、物料、补货数量、补货人、补货期限和当前状态。",
|
||
"生产计划列表中当前工序一眼可识别,且已完成、待开始、异常状态不会混淆。",
|
||
"机台任务看板能按设备查看当前任务和后续任务,当前任务字段与生产任务查询一致。",
|
||
"所有新增接口均遵循 MESCommonBase.ashx + CreateData/ExecDatabase 模式,正式库上线前在测试库完成验证。",
|
||
"所有新增代码注释和文档末尾记录满足“修改人:Ld 修改时间”规则。",
|
||
]:
|
||
add_bullet(doc, item)
|
||
|
||
add_heading(doc, "十、需要业务补充确认的问题")
|
||
for item in [
|
||
"补货订单是否必须关联“销售合同”,还是关联到“销售订单/订单编号”即可,合同通过订单反推?建议两者都保存,页面主选订单、自动带出合同。",
|
||
"安全库存补货、备品备件补货是否允许没有销售合同?如果允许,需要定义来源类型和审批/备注要求。",
|
||
"当前工序的业务定义:以“已开始未完成”为准,还是以前序完成后下一道未开始为准?建议同时显示“正在加工”和“下一待加工”。",
|
||
"机台任务看板需要显示哪些设备范围:仅精工车间设备,还是包含装配/外协/仓储相关工位?",
|
||
"是否需要在第一版支持手动调整机台任务顺序?建议第一版只展示,第二版再加受控调整和操作日志。",
|
||
"排产优先级规则:交期优先、客户优先、订单加急、设备能力、换型成本、工序等待时间,各项权重需业务确认。",
|
||
]:
|
||
add_bullet(doc, item)
|
||
|
||
add_heading(doc, "十一、推荐落地口径")
|
||
add_para(doc, "建议第一版不要直接宣传为“自动排产”,而定义为“排产可视化与任务追溯增强”。先把补货来源、当前工序、机台任务三块数据打通,现场使用一周后再根据实际反馈调整排产规则。这样既能快速解决当前痛点,也能为后续真正的排产优化算法沉淀可靠数据。")
|
||
|
||
add_para(doc, f"修改人:Ld 修改时间:{MOD_TIME};")
|
||
|
||
doc.save(OUTPUT)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|