# 修改人: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()