同步页面权限、业务功能、SQL脚本及项目文档
This commit is contained in:
275
gptlog-process/build_purchase_inbound_plan_doc.py
Normal file
275
gptlog-process/build_purchase_inbound_plan_doc.py
Normal file
@@ -0,0 +1,275 @@
|
||||
# 修改人: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()
|
||||
Reference in New Issue
Block a user