Files
JY1.0/gptlog-process/build_purchase_inbound_plan_doc.py

276 lines
16 KiB
Python
Raw 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.
# 修改人:Ld 修改时间:2026-09-02 15:59:41; 生成采购合同查询页面入库单及标签改造方案Word文档。
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Inches, Pt, RGBColor
OUTPUT = r"D:\景耀\JY1.0\gptlog-process\PurchasingManagement_OrderInquiry_生成入库单及标签方案.docx"
MODIFY_TIME = "2026-09-02 15:59:41"
def set_cell_shading(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_width(cell, width_dxa):
tc_pr = cell._tc.get_or_add_tcPr()
tc_w = tc_pr.first_child_found_in("w:tcW")
if tc_w is None:
tc_w = OxmlElement("w:tcW")
tc_pr.append(tc_w)
tc_w.set(qn("w:w"), str(width_dxa))
tc_w.set(qn("w:type"), "dxa")
def set_table_borders(table, color="A6A6A6", size="4"):
tbl_pr = table._tbl.tblPr
borders = tbl_pr.first_child_found_in("w:tblBorders")
if borders is None:
borders = OxmlElement("w:tblBorders")
tbl_pr.append(borders)
for edge in ("top", "left", "bottom", "right", "insideH", "insideV"):
tag = "w:{}".format(edge)
element = borders.find(qn(tag))
if element is None:
element = OxmlElement(tag)
borders.append(element)
element.set(qn("w:val"), "single")
element.set(qn("w:sz"), size)
element.set(qn("w:space"), "0")
element.set(qn("w:color"), color)
def set_table_width(table, width_dxa=9360, indent_dxa=120):
tbl_pr = table._tbl.tblPr
tbl_w = tbl_pr.first_child_found_in("w:tblW")
if tbl_w is None:
tbl_w = OxmlElement("w:tblW")
tbl_pr.append(tbl_w)
tbl_w.set(qn("w:w"), str(width_dxa))
tbl_w.set(qn("w:type"), "dxa")
tbl_ind = tbl_pr.first_child_found_in("w:tblInd")
if tbl_ind is None:
tbl_ind = OxmlElement("w:tblInd")
tbl_pr.append(tbl_ind)
tbl_ind.set(qn("w:w"), str(indent_dxa))
tbl_ind.set(qn("w:type"), "dxa")
def add_heading(doc, text, level=1):
paragraph = doc.add_heading(text, level=level)
for run in paragraph.runs:
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.color.rgb = RGBColor(46, 116, 181) if level <= 2 else RGBColor(31, 77, 120)
return paragraph
def add_body(doc, text):
paragraph = doc.add_paragraph()
paragraph.paragraph_format.space_after = Pt(6)
paragraph.paragraph_format.line_spacing = 1.1
run = paragraph.add_run(text)
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(11)
return paragraph
def add_bullet(doc, text):
paragraph = doc.add_paragraph(style="List Bullet")
paragraph.paragraph_format.space_after = Pt(4)
run = paragraph.add_run(text)
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(11)
return paragraph
def add_number(doc, text):
paragraph = doc.add_paragraph(style="List Number")
paragraph.paragraph_format.space_after = Pt(4)
run = paragraph.add_run(text)
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(11)
return paragraph
def add_table(doc, headers, rows, widths):
table = doc.add_table(rows=1, cols=len(headers))
table.alignment = WD_TABLE_ALIGNMENT.LEFT
table.autofit = False
set_table_width(table)
set_table_borders(table)
hdr = table.rows[0].cells
for idx, text in enumerate(headers):
hdr[idx].text = text
set_cell_width(hdr[idx], widths[idx])
set_cell_shading(hdr[idx], "F2F4F7")
hdr[idx].vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
for paragraph in hdr[idx].paragraphs:
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
for run in paragraph.runs:
run.font.bold = True
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(10)
for row_data in rows:
cells = table.add_row().cells
for idx, text in enumerate(row_data):
cells[idx].text = str(text)
set_cell_width(cells[idx], widths[idx])
cells[idx].vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
for paragraph in cells[idx].paragraphs:
paragraph.paragraph_format.space_after = Pt(0)
for run in paragraph.runs:
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(10)
doc.add_paragraph()
return table
def build():
doc = Document()
section = doc.sections[0]
section.page_width = Inches(8.5)
section.page_height = Inches(11)
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
styles["Normal"].font.name = "Calibri"
styles["Normal"]._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
styles["Normal"].font.size = Pt(11)
styles["Normal"].paragraph_format.space_after = Pt(6)
styles["Normal"].paragraph_format.line_spacing = 1.1
title = doc.add_paragraph()
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
title.paragraph_format.space_after = Pt(3)
run = title.add_run("采购合同查询页面生成入库单及标签功能实施方案")
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(20)
run.font.bold = True
run.font.color.rgb = RGBColor(11, 37, 69)
subtitle = doc.add_paragraph()
subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
subtitle.paragraph_format.space_after = Pt(12)
run = subtitle.add_run("适用页面:PurchasingManagement / OrderInquiry")
run.font.name = "Calibri"
run._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
run.font.size = Pt(11)
run.font.color.rgb = RGBColor(85, 85, 85)
add_heading(doc, "一、现状判断", 1)
add_body(doc, "当前 OrderInquiry 页面顶部已有“生成入库单”按钮,点击后打开生成入库单弹窗;弹窗需先选择供应商和合同号,再查询合同明细,最后提交到后端接口“采购管理_到货内容_新增”。")
add_body(doc, "页面右侧合同明细表通过“采购管理_采购合同明细_全部_查询数据”加载;移动端 PurchaseInboundCreateMobile 页面也复用了“仓储管理_采购入库合同_查询”“采购管理_采购入库合同明细_查询”“采购管理_到货内容_新增”这一套生成入库单流程。仓储入库记录页已经存在 WebSocket 条码打印链路,可作为标签打印的落地参考。")
add_heading(doc, "二、需求目标", 1)
add_bullet(doc, "需求一:生成入库单成功后,同步生成入库单信息标签。标签包含采购合同号、供应商、批次号、二维码;扫描二维码后可查看入库明细,字段包含物料名称、图号、数量。")
add_bullet(doc, "需求二:将 OrderInquiry 页面现有顶部“生成入库单”入口调整到左侧合同列表的操作列。用户点击某一合同的按钮后,弹窗直接展示该合同下可入库明细,用户勾选物料并填写本次数量后生成入库单。")
add_heading(doc, "三、推荐落地方案", 1)
add_body(doc, "推荐采用“以入库单号/标签ID为二维码主键,扫码后实时查询明细”的方案。二维码不直接塞入全部明细,而是保存短链接或短JSON,例如 {type:'purchaseInbound', inboundNo:'RK20260902001'}。扫码端通过入库单号查询后端,展示该入库单对应的物料名称、图号和数量。这样二维码更短,打印稳定,后续明细修正也能以数据库为准。")
add_heading(doc, "四、页面交互调整", 1)
add_table(
doc,
["位置", "现状", "调整方案"],
[
["顶部工具栏", "存在“生成入库单”按钮,需重新选择供应商和合同。", "建议移除或隐藏该入口,避免用户脱离当前合同上下文重复选择。"],
["左侧合同列表操作列", "已有打印、删除、打回、图片查看/上传等按钮。", "新增“生成入库单”图标按钮,点击后传入当前合同行。按钮建议放在打印按钮之后,并加 tooltip。"],
["生成弹窗", "弹窗内选择供应商、合同号后再查询明细。", "改为打开时自动带入合同流水号、采购合同号、供应商流水号、供应商名称,并直接查询该合同可入库明细。"],
["明细选择", "表格行填写到货数量和是否质检。", "增加勾选列;默认只提交已勾选且数量大于0的行。数量最大值限制为采购数-已到数。"],
["提交成功", "提示成功并关闭弹窗。", "提交成功后刷新合同列表和右侧明细,同时弹出/预览入库标签,支持打印标签。"]
],
[1600, 3100, 4660]
)
add_heading(doc, "五、前端改造点", 1)
add_number(doc, "在 src/views/PurchasingManagement/OrderInquiry/index.vue 左侧合同列表操作列新增按钮,例如“入库单”按钮,调用 openArrivalDialog(scope.row)。")
add_number(doc, "新增或改造 openArrivalDialog(row):清空弹窗数据,记录 row.采购合同流水号、row.采购合同号、row.供应商、row.供应商流水号,设置 arrivalContractNo、arrivalContractLabel、arrivalSupplierName,并立即调用 searchArrivalDetailByContract(row)。")
add_number(doc, "保留原 searchArrivalDetail 的核心接口,但改为无需用户再选供应商/合同;接口参数仍传“供应商流水号”和“采购合同流水号”。")
add_number(doc, "弹窗表格增加 selection 列,数量输入框使用 el-input-number,max 取 getCanArrivalCount(row),提交前校验选择行、数量、可入库数。")
add_number(doc, "submitArrivalNotice 成功后,从后端返回值或当前入库单号组装 labelInfo,并调用 openInboundLabel(labelInfo) 或 printInboundLabel(labelInfo)。")
add_number(doc, "二维码生成可使用项目已有 qrcode 包,在组件中 import QRCode from 'qrcode',通过 QRCode.toDataURL(qrContent) 生成图片地址。项目为 Vue 2,不使用 Composition API。")
add_heading(doc, "六、后端和数据库建议", 1)
add_table(
doc,
["对象", "建议内容", "说明"],
[
["生成入库单接口", "调整“采购管理_到货内容_新增”返回入库单号、批次号、入库单流水号或标签ID。", "前端生成标签必须拿到稳定主键;如果当前只返回 result,需要后端补充返回字段。"],
["扫码查询接口", "新增“采购管理_入库单标签_扫码查询”或“仓储管理_入库单标签_扫码查询”。", "参数传入入库单号或标签ID,返回采购合同号、供应商、批次号、明细数组。"],
["标签记录表", "可新增“仓储管理_入库单标签”表,保存标签ID、入库单号、采购合同流水号、供应商流水号、批次号、二维码内容、创建人、创建时间。", "便于后续重打、追溯、作废和扫码统计。"],
["明细关联", "标签明细关联入库单明细或到货明细。", "不要只保存前端传来的文本,避免后续库存/入库记录追溯断链。"]
],
[1900, 4300, 3160]
)
add_heading(doc, "七、二维码内容设计", 1)
add_body(doc, "推荐二维码内容采用短格式,避免中文明细直接写入二维码。可选方案如下:")
add_bullet(doc, "方案A:短链接。例如 http://服务器地址/#/PurchaseInboundScan?inboundNo=入库单号。适合手机/PDA直接打开页面。")
add_bullet(doc, "方案B:短JSON。例如 {\"t\":\"RK\",\"no\":\"入库单号\"}。适合扫码枪输入后由系统解析。")
add_bullet(doc, "方案C:标签ID。例如 JYRK|标签ID。适合内网扫码后统一调用查询接口。")
add_body(doc, "建议优先采用方案C或方案B,扫码端再调用后端接口返回明细。若已有 PDA 扫码页面,可新增一个轻量查询页面,只显示采购合同号、供应商、批次号,以及物料名称、图号、数量列表。")
add_heading(doc, "八、标签打印方案", 1)
add_body(doc, "标签内容建议为 80mm x 50mm 或按现有标签纸规格确定,布局如下:顶部显示“采购入库标签”,中部显示采购合同号、供应商、批次号,右侧或下方显示二维码,底部显示入库单号和生成时间。若同一入库单包含多条明细,标签只打印汇总信息,明细通过扫码查询。")
add_body(doc, "打印落地有两种可执行方式:第一种是页面隐藏打印模板,通过 window.print 打印普通标签;第二种是复用仓储记录页已有 WebSocket 指令发送到标签打印服务。若现场标签打印机已接入 WebSocket,建议采用第二种,新增 JY_PurchaseInbound_Label 模板,字段包含 QRCode、合同号、供应商、批次号、入库单号。")
add_heading(doc, "九、接口参数建议", 1)
add_table(
doc,
["阶段", "接口 name", "主要参数", "返回建议"],
[
["打开弹窗查询明细", "采购管理_采购入库合同明细_查询", "供应商流水号、采购合同流水号", "物料流水号、采购合同明细流水号、采购数、已到数、入库单号、物料名称/采购件、图号或型号"],
["提交生成入库单", "采购管理_到货内容_新增", "通知内容、发起人、采购合同流水号、到货数组、物料流水号组、质检标志组、采购合同、供应商流水号、入库单号", "result、入库单号、批次号、入库单流水号、标签ID"],
["扫码查询标签", "采购管理_入库单标签_扫码查询", "入库单号或标签ID", "采购合同号、供应商、批次号、明细:物料名称、图号、数量"]
],
[1700, 2600, 3150, 1910]
)
add_heading(doc, "十、实施步骤", 1)
for item in [
"后端确认生成入库单接口是否能返回入库单号和批次号;若不能,先补返回字段。",
"后端新增或确认扫码查询接口,保证通过入库单号/标签ID能查到入库明细。",
"前端将 OrderInquiry 顶部生成入口改到左侧合同操作列,点击后自动带入当前合同。",
"前端改造弹窗为当前合同明细选择模式,增加勾选、数量校验、可入库数限制。",
"前端接入 qrcode 生成二维码 DataURL,完成标签预览和打印。",
"联调:合同选择、部分入库、超量限制、质检/直入库、标签重打、扫码查询、刷新状态。",
"测试通过后再根据现场打印机模板微调标签尺寸和字段位置。"
]:
add_number(doc, item)
add_heading(doc, "十一、风险和注意事项", 1)
add_bullet(doc, "批次号的生成位置必须以后端为准,前端只展示和打印,避免并发生成时重复。")
add_bullet(doc, "同一合同允许多次部分入库时,二维码必须绑定入库单号或标签ID,而不能只绑定采购合同号。")
add_bullet(doc, "提交前必须用“采购数-已到数”限制本次数量;后端也要再次校验,防止多端并发超入。")
add_bullet(doc, "如果标签需要“一物料一标签”,则提交成功后应按入库明细逐条生成标签;如果只需要“一入库单一标签”,则标签为汇总标签,扫码查看全部明细。建议先落地“一入库单一标签”。")
add_heading(doc, "十二、建议结论", 1)
add_body(doc, "该需求可以在现有架构内落地,不需要改造项目技术栈。前端主要改 OrderInquiry 页面入口和弹窗交互,二维码使用现有 qrcode 依赖生成;后端需要补强生成入库单后的返回字段,并提供扫码查询接口。推荐先实现“一合同操作入口 + 明细选择生成 + 一入库单一标签 + 扫码查询明细”的版本,后续如现场需要再扩展为“一明细一标签”或“标签重打管理”。")
doc.add_paragraph()
add_body(doc, "修改人:Ld 修改时间:{};".format(MODIFY_TIME))
doc.save(OUTPUT)
if __name__ == "__main__":
build()