feat(pl): 按单据类型限制打印项并调整送(提)货单布局
按入库/出库/直销限制可打印单据;送(提)货单信息区改为一行布局,物料表增加单据编号列,并修正条款列宽与类型多选不换行。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
1e2e8ab0fc
commit
70bdd820ce
4 files changed
+367
-191
No files matched your search
@@ -29,17 +29,18 @@ const INFO_COLGROUP = `<colgroup>
|
||||
<col span="7" style="width:14.28%;" />
|
||||
</colgroup>`
|
||||
/**
|
||||
* 物料表列宽:加宽编号/名称,收窄规格/单位;前 5 列合计供条款区使用。
|
||||
* 物料编号 / 物料名称 / 规格 / 单位 / 数量 / 产品规格 / 实收数量
|
||||
* 物料表列宽:单据编号 + 加宽编号/名称,收窄规格/单位;前 5 列合计供条款区使用。
|
||||
* 单据编号 / 物料编号 / 物料名称 / 规格 / 单位 / 数量 / 产品规格 / 实收数量
|
||||
*/
|
||||
const PRODUCT_COLGROUP = `<colgroup>
|
||||
<col style="width:18%;" />
|
||||
<col style="width:24%;" />
|
||||
<col style="width:14%;" />
|
||||
<col style="width:14%;" />
|
||||
<col style="width:20%;" />
|
||||
<col style="width:8%;" />
|
||||
<col style="width:6%;" />
|
||||
<col style="width:12%;" />
|
||||
<col style="width:16%;" />
|
||||
<col style="width:16%;" />
|
||||
<col style="width:10%;" />
|
||||
<col style="width:14%;" />
|
||||
<col style="width:14%;" />
|
||||
</colgroup>`
|
||||
|
||||
/** 物料网格 padding(编辑器预览) */
|
||||
@@ -87,9 +88,9 @@ const INFO_VALUE_INLINE_LEFT = `flex:1;min-width:0;box-sizing:border-box;border-
|
||||
const INFO_VALUE_INLINE_CENTER = `flex:1;min-width:0;box-sizing:border-box;border-bottom:${INFO_UNDERLINE} !important;padding:0 2px 2px;text-align:center;min-height:1.3em;`
|
||||
const INFO_CELL_LEFT = `${NO_BORDER}text-align:left;`
|
||||
const INFO_CELL_RIGHT = `${NO_BORDER}text-align:left;`
|
||||
const INFO_GAP_BEFORE_PRODUCT = 24
|
||||
const INFO_GAP_BEFORE_PRODUCT = 12
|
||||
const GAP_BEFORE_PRODUCT_CELL = `border:none !important;padding:0 !important;line-height:0 !important;font-size:0 !important;background:transparent !important;height:${INFO_GAP_BEFORE_PRODUCT}px !important;min-height:${INFO_GAP_BEFORE_PRODUCT}px !important;`
|
||||
const INFO_GAP_BEFORE_SIGN = 24
|
||||
const INFO_GAP_BEFORE_SIGN = 12
|
||||
const GAP_BEFORE_SIGN_CELL = `border:none !important;padding:0 !important;line-height:0 !important;font-size:0 !important;background:transparent !important;height:${INFO_GAP_BEFORE_SIGN}px !important;min-height:${INFO_GAP_BEFORE_SIGN}px !important;`
|
||||
const SIDE_LABELS_COL_WIDTH = 36
|
||||
|
||||
@@ -99,7 +100,7 @@ function buildDeliverySlipSignItem(label: string, valueContent: string, minWidth
|
||||
|
||||
function buildDeliverySlipSignRowHtml(): string {
|
||||
return `<tr class="delivery-slip-sign-row">
|
||||
<td colspan="7" class="delivery-slip-sign-row-cell" style="border:none !important;padding:${TABLE_ROW_PADDING};text-align:center;${FONT_SIGN}background:transparent !important;">
|
||||
<td colspan="8" class="delivery-slip-sign-row-cell" style="border:none !important;padding:${TABLE_ROW_PADDING};text-align:center;${FONT_SIGN}background:transparent !important;">
|
||||
<div class="delivery-slip-sign-inner">
|
||||
${buildDeliverySlipSignItem('仓库:', ' ', '80px')}
|
||||
${buildDeliverySlipSignItem('审核:', ' ', '80px')}
|
||||
@@ -165,15 +166,22 @@ function formatDeliverySlipProductGridCellContent(content: string): string {
|
||||
return plain || ' '
|
||||
}
|
||||
|
||||
function buildProductRows(products: PlanProduct[] = [], ctx?: DeliverySlipRenderContext): string {
|
||||
function buildProductRows(
|
||||
products: PlanProduct[] = [],
|
||||
planNo = '',
|
||||
ctx?: DeliverySlipRenderContext
|
||||
): string {
|
||||
if (!products.length) {
|
||||
return `<tr><td class="delivery-slip-product-cell" colspan="7" style="${PRODUCT_CELL}">暂无产品信息</td></tr>`
|
||||
return `<tr><td class="delivery-slip-product-cell" colspan="8" style="${PRODUCT_CELL}">暂无产品信息</td></tr>`
|
||||
}
|
||||
|
||||
const planNoText = formatDeliverySlipProductGridCellContent(planNo)
|
||||
|
||||
const dataRows = products
|
||||
.map((product) => {
|
||||
const qty = product.outboundQty ?? product.outboundEstimateQty ?? product.quantity ?? ''
|
||||
return `<tr>
|
||||
<td class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_GRID_CELL}">${planNoText}</td>
|
||||
<td class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_GRID_CELL}">${formatDeliverySlipProductGridCellContent(resolveSlipProductCode(product, ctx))}</td>
|
||||
<td class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_GRID_CELL}">${formatDeliverySlipProductGridCellContent(product.productName || '')}</td>
|
||||
<td class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_GRID_CELL}">${formatDeliverySlipProductGridCellContent(product.model || '')}</td>
|
||||
@@ -220,13 +228,14 @@ export const DELIVERY_SLIP_PRINT_CSS = `
|
||||
flex: 1 !important;
|
||||
min-width: 0 !important;
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
flex-wrap: nowrap !important;
|
||||
justify-content: flex-start !important;
|
||||
align-items: center !important;
|
||||
gap: 14px 18px !important;
|
||||
gap: 10px 12px !important;
|
||||
box-sizing: border-box !important;
|
||||
font-size: 20px !important;
|
||||
line-height: 1.35 !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
.delivery-slip-doc .delivery-slip-type-check-item {
|
||||
display: inline-flex !important;
|
||||
@@ -577,17 +586,44 @@ const SIDE_LABEL_CELL = `border:none !important;padding:0 !important;vertical-al
|
||||
|
||||
const DELIVERY_SLIP_TYPE_CHECK_WRAP_STYLE = `${INFO_ROW}margin-top:-8px;margin-bottom:20px;`
|
||||
const DELIVERY_SLIP_TYPE_CHECK_INNER_STYLE =
|
||||
'flex:1;min-width:0;display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:14px 18px;box-sizing:border-box;font-size:20px;line-height:1.35;'
|
||||
'flex:1;min-width:0;display:flex;flex-wrap:nowrap;justify-content:flex-start;align-items:center;gap:10px 12px;box-sizing:border-box;font-size:20px;line-height:1.35;white-space:nowrap;'
|
||||
|
||||
function buildDeliverySlipTypeCheckboxesHtml(): string {
|
||||
const item = (label: string) =>
|
||||
`<label class="delivery-slip-type-check-item" contenteditable="false"><input type="checkbox" class="delivery-slip-type-check-input" />${label}</label>`
|
||||
return `<div class="delivery-slip-info-row delivery-slip-type-check-wrap" style="${DELIVERY_SLIP_TYPE_CHECK_WRAP_STYLE}">
|
||||
<span class="delivery-slip-info-label delivery-slip-type-check-spacer" style="${INFO_LABEL}visibility:hidden;">单据编号:</span>
|
||||
<span class="delivery-slip-info-label delivery-slip-type-check-spacer" style="${INFO_LABEL}visibility:hidden;">日 期:</span>
|
||||
<div class="delivery-slip-type-check-row" style="${DELIVERY_SLIP_TYPE_CHECK_INNER_STYLE}">${item('自提')}${item('出库')}${item('直销')}</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
function buildDeliverySlipInfoTableHtml(): string {
|
||||
return `<table class="delivery-slip-info-table" style="width:100%;border-collapse:collapse;table-layout:fixed;border:none !important;">
|
||||
${INFO_COLGROUP}
|
||||
<tr>
|
||||
<td colspan="2" style="${INFO_CELL_LEFT}">
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">收货单位:</span>
|
||||
<span class="delivery-slip-info-value-left" style="${INFO_VALUE_INLINE_LEFT}">{{receivingUnit}} </span>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="2" style="${INFO_CELL_LEFT}">
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">收货联系方式:</span>
|
||||
<span class="delivery-slip-info-value-left" style="${INFO_VALUE_INLINE_LEFT}">{{receiveContact}} </span>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="3" style="${INFO_CELL_RIGHT}">
|
||||
${buildDeliverySlipTypeCheckboxesHtml()}
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">日 期:</span>
|
||||
<span class="delivery-slip-info-value-center" style="${INFO_VALUE_INLINE_CENTER}">{{planDateChinese}} </span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`
|
||||
}
|
||||
|
||||
function buildDeliverySlipTermsHtml(): string {
|
||||
return `<div class="delivery-slip-terms-text" style="${TERMS_TEXT_STYLE}">
|
||||
1.本送货单如购销双方未签订合同,视为有效;<br />
|
||||
@@ -622,38 +658,7 @@ export function generateDeliverySlipTemplate(_plan?: Plan): string {
|
||||
<tr>
|
||||
<td class="delivery-slip-main-col" style="vertical-align:top;padding-right:6px;border:none !important;background:transparent !important;">
|
||||
<!-- 1. 基本信息(独立表,不可拖宽高) -->
|
||||
<table class="delivery-slip-info-table" style="width:100%;border-collapse:collapse;table-layout:fixed;border:none !important;">
|
||||
${INFO_COLGROUP}
|
||||
<tr>
|
||||
<td colspan="4" style="${INFO_CELL_LEFT}">
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">收货单位:</span>
|
||||
<span class="delivery-slip-info-value-left" style="${INFO_VALUE_INLINE_LEFT}">{{receivingUnit}} </span>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="3" style="${INFO_CELL_RIGHT}">
|
||||
${buildDeliverySlipTypeCheckboxesHtml()}
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">单据编号:</span>
|
||||
<span class="delivery-slip-info-value-center" style="${INFO_VALUE_INLINE_CENTER}">{{planNo}} </span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" style="${INFO_CELL_LEFT}">
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">收货联系方式:</span>
|
||||
<span class="delivery-slip-info-value-left" style="${INFO_VALUE_INLINE_LEFT}">{{receiveContact}} </span>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="3" style="${INFO_CELL_RIGHT}">
|
||||
<div class="delivery-slip-info-row" style="${INFO_ROW}">
|
||||
<span class="delivery-slip-info-label" style="${INFO_LABEL}">日 期:</span>
|
||||
<span class="delivery-slip-info-value-center" style="${INFO_VALUE_INLINE_CENTER}">{{planDateChinese}} </span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
${buildDeliverySlipInfoTableHtml()}
|
||||
|
||||
<div class="delivery-slip-section-gap delivery-slip-gap-before-product" style="${GAP_BEFORE_PRODUCT_CELL}"> </div>
|
||||
|
||||
@@ -661,6 +666,7 @@ export function generateDeliverySlipTemplate(_plan?: Plan): string {
|
||||
<table class="delivery-slip-product-table" style="width:100%;border-collapse:collapse;table-layout:fixed;border:none !important;">
|
||||
${PRODUCT_COLGROUP}
|
||||
<tr class="delivery-slip-product-header">
|
||||
<th class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_TH}">单据编号</th>
|
||||
<th class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_TH}">物料编号</th>
|
||||
<th class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_TH}">物料名称</th>
|
||||
<th class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_TH}">规格</th>
|
||||
@@ -671,7 +677,7 @@ export function generateDeliverySlipTemplate(_plan?: Plan): string {
|
||||
</tr>
|
||||
{{productTable}}
|
||||
<tr>
|
||||
<td colspan="7" class="delivery-slip-product-cell" style="${PRODUCT_TABLE_CELL_LEFT}">
|
||||
<td colspan="8" class="delivery-slip-product-cell" style="${PRODUCT_TABLE_CELL_LEFT}">
|
||||
备注:{{remark}}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -679,7 +685,7 @@ export function generateDeliverySlipTemplate(_plan?: Plan): string {
|
||||
<td colspan="5" class="delivery-slip-product-cell delivery-slip-terms-cell" style="${PRODUCT_TERMS_CELL_LEFT}">
|
||||
${buildDeliverySlipTermsHtml()}
|
||||
</td>
|
||||
<td colspan="2" class="delivery-slip-product-cell" style="${PRODUCT_TABLE_CELL_LEFT}">
|
||||
<td colspan="3" class="delivery-slip-product-cell" style="${PRODUCT_TABLE_CELL_LEFT}">
|
||||
${SEAL_BLOCK}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -781,7 +787,7 @@ function patchDeliverySlipProductGridCellAttrs(attrs: string): string {
|
||||
function normalizeDeliverySlipProductGridCell(html: string): string {
|
||||
if (!html.includes('delivery-slip-doc') || !html.includes('delivery-slip-product-cell')) return html
|
||||
|
||||
let result = html.replace(/<tr([^>]*)>\s*(<th[\s\S]*?<\/th>\s*){7}\s*<\/tr>/g, (rowMatch) => {
|
||||
let result = html.replace(/<tr([^>]*)>\s*(<th[\s\S]*?<\/th>\s*){8}\s*<\/tr>/g, (rowMatch) => {
|
||||
if (!rowMatch.includes('物料编号') || rowMatch.includes('colspan')) return rowMatch
|
||||
let row = rowMatch.includes('delivery-slip-product-header')
|
||||
? rowMatch
|
||||
@@ -791,7 +797,7 @@ function normalizeDeliverySlipProductGridCell(html: string): string {
|
||||
})
|
||||
})
|
||||
|
||||
result = result.replace(/<tr([^>]*)>\s*(<td(?![^>]*colspan)[^>]*>[\s\S]*?<\/td>\s*){7}\s*<\/tr>/g, (rowMatch) => {
|
||||
result = result.replace(/<tr([^>]*)>\s*(<td(?![^>]*colspan)[^>]*>[\s\S]*?<\/td>\s*){8}\s*<\/tr>/g, (rowMatch) => {
|
||||
if (
|
||||
rowMatch.includes('备注') ||
|
||||
rowMatch.includes('1.本送货单') ||
|
||||
@@ -1120,9 +1126,10 @@ function normalizeDeliverySlipProductTableFooter(html: string): string {
|
||||
|
||||
let result = html
|
||||
|
||||
result = result.replace(/<td([^>]*colspan="7"[^>]*)>(\s*)备注:/g, (_match, attrs, space) => {
|
||||
result = result.replace(/<td([^>]*colspan="[78]"[^>]*)>(\s*)备注:/g, (_match, attrs, space) => {
|
||||
const withSpan = String(attrs).replace(/colspan="[78]"/, 'colspan="8"')
|
||||
const patched = patchProductFooterCellAttrs(
|
||||
attrs,
|
||||
withSpan,
|
||||
'delivery-slip-product-cell',
|
||||
PRODUCT_TABLE_CELL_LEFT
|
||||
)
|
||||
@@ -1130,9 +1137,9 @@ function normalizeDeliverySlipProductTableFooter(html: string): string {
|
||||
})
|
||||
|
||||
result = result.replace(
|
||||
/<td([^>]*colspan="[45]"[^>]*)>\s*(<div class="delivery-slip-terms-text"|\s*1\.本送货单)/g,
|
||||
/<td([^>]*colspan="[456]"[^>]*)>\s*(<div class="delivery-slip-terms-text"|\s*1\.本送货单)/g,
|
||||
(_match, attrs, contentStart) => {
|
||||
const withSpan = String(attrs).replace(/colspan="[45]"/, 'colspan="5"')
|
||||
const withSpan = String(attrs).replace(/colspan="[456]"/, 'colspan="5"')
|
||||
const patched = patchProductFooterCellAttrs(
|
||||
withSpan,
|
||||
'delivery-slip-product-cell delivery-slip-terms-cell',
|
||||
@@ -1145,7 +1152,7 @@ function normalizeDeliverySlipProductTableFooter(html: string): string {
|
||||
result = result.replace(
|
||||
/<td([^>]*colspan="[23]"[^>]*)>\s*<div class="delivery-slip-seal-block"/g,
|
||||
(_match, attrs) => {
|
||||
const withSpan = String(attrs).replace(/colspan="[23]"/, 'colspan="2"')
|
||||
const withSpan = String(attrs).replace(/colspan="[23]"/, 'colspan="3"')
|
||||
const patched = patchProductFooterCellAttrs(withSpan, 'delivery-slip-product-cell', PRODUCT_TABLE_CELL_LEFT)
|
||||
return `<td${patched}>\n <div class="delivery-slip-seal-block"`
|
||||
}
|
||||
@@ -1176,7 +1183,7 @@ function normalizeDeliverySlipTermsCell(html: string): string {
|
||||
}
|
||||
|
||||
let result = html.replace(
|
||||
/<td colspan="[45]"([^>]*)>\s*<div class="delivery-slip-terms-text"/g,
|
||||
/<td colspan="[456]"([^>]*)>\s*<div class="delivery-slip-terms-text"/g,
|
||||
(match, attrs) => {
|
||||
if (attrs.includes('delivery-slip-terms-cell') && attrs.includes('border:0.3px solid #000') && /colspan="5"/.test(match)) {
|
||||
return match
|
||||
@@ -1227,10 +1234,15 @@ function normalizeDeliverySlipTermsText(html: string): string {
|
||||
|
||||
/** 刷新已有间距行的 inline 样式(TinyMCE 保存后可能丢失) */
|
||||
function refreshDeliverySlipGapBeforeProduct(html: string): string {
|
||||
return html.replace(
|
||||
/<tr class="delivery-slip-gap-before-product">[\s\S]*?<\/tr>/,
|
||||
`<tr class="delivery-slip-gap-before-product">\n <td colspan="7" class="delivery-slip-gap-before-product-cell" style="${GAP_BEFORE_PRODUCT_CELL}"> </td>\n </tr>`
|
||||
)
|
||||
return html
|
||||
.replace(
|
||||
/<tr class="delivery-slip-gap-before-product">[\s\S]*?<\/tr>/,
|
||||
`<tr class="delivery-slip-gap-before-product">\n <td colspan="8" class="delivery-slip-gap-before-product-cell" style="${GAP_BEFORE_PRODUCT_CELL}"> </td>\n </tr>`
|
||||
)
|
||||
.replace(
|
||||
/<div class="delivery-slip-section-gap delivery-slip-gap-before-product"[^>]*>[\s\S]*?<\/div>/,
|
||||
`<div class="delivery-slip-section-gap delivery-slip-gap-before-product" style="${GAP_BEFORE_PRODUCT_CELL}"> </div>`
|
||||
)
|
||||
}
|
||||
|
||||
/** 在收货联系方式行与物料表之间插入间距行(兼容已保存模板) */
|
||||
@@ -1243,32 +1255,42 @@ function normalizeDeliverySlipGapBeforeProduct(html: string): string {
|
||||
return refreshDeliverySlipGapBeforeProduct(html)
|
||||
}
|
||||
|
||||
const gapRow = `<tr class="delivery-slip-gap-before-product"><td colspan="7" class="delivery-slip-gap-before-product-cell" style="${GAP_BEFORE_PRODUCT_CELL}"> </td></tr>\n `
|
||||
const gapRow = `<tr class="delivery-slip-gap-before-product"><td colspan="8" class="delivery-slip-gap-before-product-cell" style="${GAP_BEFORE_PRODUCT_CELL}"> </td></tr>\n `
|
||||
const productHeader = `(?:单据编号|物料编号)`
|
||||
|
||||
const withComment = html.replace(
|
||||
/(<span class="delivery-slip-info-label"[^>]*>日(?: )?期:<\/span>[\s\S]*?<\/tr>\s*)(<!--\s*中:产品明细表[\s\S]*?<tr>\s*<th[^>]*>物料编号)/,
|
||||
new RegExp(
|
||||
`(收货联系方式:[\\s\\S]*?<\\/tr>\\s*)(<!--\\s*中:产品明细表[\\s\\S]*?<tr[\\s\\S]*?<th[^>]*>${productHeader})`
|
||||
),
|
||||
`$1${gapRow}$2`
|
||||
)
|
||||
if (withComment !== html) return withComment
|
||||
|
||||
const withHeader = html.replace(
|
||||
/(<span class="delivery-slip-info-label"[^>]*>日(?: )?期:<\/span>[\s\S]*?<\/tr>\s*)(<tr>\s*<th[^>]*>物料编号)/,
|
||||
new RegExp(`(收货联系方式:[\\s\\S]*?<\\/tr>\\s*)(<tr[\\s\\S]*?<th[^>]*>${productHeader})`),
|
||||
`$1${gapRow}$2`
|
||||
)
|
||||
if (withHeader !== html) return withHeader
|
||||
|
||||
return html.replace(
|
||||
/(收货联系方式:[\s\S]*?<\/tr>\s*)(<!--\s*中:产品明细表[\s\S]*?<tr>\s*<th[^>]*>物料编号|<tr>\s*<th[^>]*>物料编号)/,
|
||||
new RegExp(
|
||||
`(<span class="delivery-slip-info-label"[^>]*>日(?: )?期:<\\/span>[\\s\\S]*?<\\/tr>\\s*)(<!--\\s*中:产品明细表[\\s\\S]*?<tr[\\s\\S]*?<th[^>]*>${productHeader}|<tr[\\s\\S]*?<th[^>]*>${productHeader})`
|
||||
),
|
||||
`$1${gapRow}$2`
|
||||
)
|
||||
}
|
||||
|
||||
/** 刷新签字区上方间距行 inline 样式 */
|
||||
function refreshDeliverySlipGapBeforeSign(html: string): string {
|
||||
return html.replace(
|
||||
/<tr class="delivery-slip-gap-before-sign">[\s\S]*?<\/tr>/,
|
||||
`<tr class="delivery-slip-gap-before-sign">\n <td colspan="7" class="delivery-slip-gap-before-sign-cell" style="${GAP_BEFORE_SIGN_CELL}"> </td>\n </tr>`
|
||||
)
|
||||
return html
|
||||
.replace(
|
||||
/<tr class="delivery-slip-gap-before-sign">[\s\S]*?<\/tr>/,
|
||||
`<tr class="delivery-slip-gap-before-sign">\n <td colspan="8" class="delivery-slip-gap-before-sign-cell" style="${GAP_BEFORE_SIGN_CELL}"> </td>\n </tr>`
|
||||
)
|
||||
.replace(
|
||||
/<div class="delivery-slip-section-gap delivery-slip-gap-before-sign"[^>]*>[\s\S]*?<\/div>/,
|
||||
`<div class="delivery-slip-section-gap delivery-slip-gap-before-sign" style="${GAP_BEFORE_SIGN_CELL}"> </div>`
|
||||
)
|
||||
}
|
||||
|
||||
/** 在物料表与签字区之间插入间距行(兼容已保存模板) */
|
||||
@@ -1279,16 +1301,16 @@ function normalizeDeliverySlipGapBeforeSign(html: string): string {
|
||||
return refreshDeliverySlipGapBeforeSign(html)
|
||||
}
|
||||
|
||||
const gapRow = `<tr class="delivery-slip-gap-before-sign"><td colspan="7" class="delivery-slip-gap-before-sign-cell" style="${GAP_BEFORE_SIGN_CELL}"> </td></tr>\n\n `
|
||||
const gapRow = `<tr class="delivery-slip-gap-before-sign"><td colspan="8" class="delivery-slip-gap-before-sign-cell" style="${GAP_BEFORE_SIGN_CELL}"> </td></tr>\n\n `
|
||||
|
||||
const withComment = html.replace(
|
||||
/(<\/tr>\s*)(<!--\s*下:签字区[\s\S]*?<tr>\s*<td colspan="7"[^>]*>\s*仓库:)/,
|
||||
/(<\/tr>\s*)(<!--\s*下:签字区[\s\S]*?<tr>\s*<td colspan="[78]"[^>]*>\s*仓库:)/,
|
||||
`$1${gapRow}$2`
|
||||
)
|
||||
if (withComment !== html) return withComment
|
||||
|
||||
return html.replace(
|
||||
/(delivery-slip-seal-block[\s\S]*?<\/tr>\s*)(<tr>\s*<td colspan="7"[^>]*>\s*仓库:)/,
|
||||
/(delivery-slip-seal-block[\s\S]*?<\/tr>\s*)(<tr>\s*<td colspan="[78]"[^>]*>\s*仓库:)/,
|
||||
`$1${gapRow}$2`
|
||||
)
|
||||
}
|
||||
@@ -1323,7 +1345,7 @@ function normalizeDeliverySlipSignRow(html: string): string {
|
||||
if (!html.includes('delivery-slip-doc') || !html.includes('仓库:')) return html
|
||||
|
||||
let result = html.replace(
|
||||
/<tr([^>]*)>\s*<td colspan="7"([^>]*)>([\s\S]*?仓库:[\s\S]*?司机\/送货人\(附车牌\)[^<]*[\s\S]*?)<\/td>\s*<\/tr>/g,
|
||||
/<tr([^>]*)>\s*<td colspan="[78]"([^>]*)>([\s\S]*?仓库:[\s\S]*?司机\/送货人\(附车牌\)[^<]*[\s\S]*?)<\/td>\s*<\/tr>/g,
|
||||
(match, trAttrs, tdAttrs, content) => {
|
||||
if (!content.includes('delivery-slip-sign-value') || content.includes('delivery-slip-sign-inner')) {
|
||||
return match
|
||||
@@ -1355,7 +1377,7 @@ function normalizeDeliverySlipSignRow(html: string): string {
|
||||
nextTdAttrs = `${nextTdAttrs} class="delivery-slip-sign-row-cell"`
|
||||
}
|
||||
|
||||
return `<tr${trClassAttr}>\n <td colspan="7"${nextTdAttrs}>\n <div class="delivery-slip-sign-inner">${wrappedContent.trim()}</div>\n </td>\n </tr>`
|
||||
return `<tr${trClassAttr}>\n <td colspan="8"${nextTdAttrs}>\n <div class="delivery-slip-sign-inner">${wrappedContent.trim()}</div>\n </td>\n </tr>`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1367,6 +1389,89 @@ function normalizeDeliverySlipSignRow(html: string): string {
|
||||
return normalizeDeliverySlipSignLabelMarkup(result)
|
||||
}
|
||||
|
||||
/** 信息区:收货单位 / 收货联系方式 / 日期 同一行(兼容旧多行布局) */
|
||||
function normalizeDeliverySlipInfoLayout(html: string): string {
|
||||
if (!html.includes('delivery-slip-info-table')) return html
|
||||
|
||||
const infoMatch = html.match(/<table class="delivery-slip-info-table"[^>]*>[\s\S]*?<\/table>/i)
|
||||
if (!infoMatch) return html
|
||||
|
||||
const infoHtml = infoMatch[0]
|
||||
const rowCount = (infoHtml.match(/<tr[\s>]/g) || []).length
|
||||
const hasPlanNoInInfo = infoHtml.includes('单据编号:')
|
||||
const dateColWideEnough = /<td[^>]*colspan="3"[^>]*>[\s\S]*?日(?: )?期:/.test(infoHtml)
|
||||
const oneRowThreeFields =
|
||||
rowCount === 1 &&
|
||||
infoHtml.includes('收货单位:') &&
|
||||
infoHtml.includes('收货联系方式:') &&
|
||||
/日(?: )?期:/.test(infoHtml) &&
|
||||
!hasPlanNoInInfo &&
|
||||
dateColWideEnough
|
||||
|
||||
if (oneRowThreeFields) return html
|
||||
|
||||
return html.replace(infoMatch[0], buildDeliverySlipInfoTableHtml())
|
||||
}
|
||||
|
||||
/** 物料表:表头补「单据编号」列,并把旧 7 列数据行升为 8 列(兼容已保存模板) */
|
||||
function normalizeDeliverySlipProductPlanNoColumn(html: string): string {
|
||||
if (!html.includes('delivery-slip-product-table')) return html
|
||||
|
||||
let result = html
|
||||
|
||||
if (!/>单据编号<\/th>/.test(result)) {
|
||||
result = result.replace(
|
||||
/(<tr[^>]*class="[^"]*delivery-slip-product-header[^"]*"[^>]*>\s*)(<th[^>]*>物料编号<\/th>)/,
|
||||
`$1<th class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_TH}">单据编号</th>\n $2`
|
||||
)
|
||||
result = result.replace(
|
||||
/(<tr>\s*)(<th[^>]*>物料编号<\/th>)/,
|
||||
`$1<th class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_TH}">单据编号</th>\n $2`
|
||||
)
|
||||
}
|
||||
|
||||
// 旧 7 列明细行:在首格前插入单据编号占位
|
||||
result = result.replace(
|
||||
/<tr([^>]*)>\s*((?:<td(?![^>]*colspan)[^>]*>[\s\S]*?<\/td>\s*){7})<\/tr>/g,
|
||||
(rowMatch, trAttrs, cells) => {
|
||||
if (
|
||||
rowMatch.includes('备注') ||
|
||||
rowMatch.includes('1.本送货单') ||
|
||||
rowMatch.includes('仓库:') ||
|
||||
rowMatch.includes('暂无产品信息') ||
|
||||
rowMatch.includes('单据编号')
|
||||
) {
|
||||
return rowMatch
|
||||
}
|
||||
return `<tr${trAttrs}>\n <td class="delivery-slip-product-cell delivery-slip-product-grid-cell" style="${PRODUCT_GRID_CELL}">{{planNo}}</td>\n ${cells}</tr>`
|
||||
}
|
||||
)
|
||||
|
||||
// 仅升级物料表内备注等跨列,条款区保持 5 列、印章区 3 列
|
||||
result = result.replace(
|
||||
/(<table class="delivery-slip-product-table"[^>]*>)([\s\S]*?)(<\/table>)/i,
|
||||
(_m, open, inner, close) => {
|
||||
let nextInner = String(inner).replace(/colspan="7"/g, 'colspan="8"')
|
||||
nextInner = nextInner.replace(
|
||||
/(<td[^>]*colspan=")6("[^>]*>\s*(?:<div class="delivery-slip-terms-text"|[\s]*1\.本送货单))/g,
|
||||
'$15$2'
|
||||
)
|
||||
nextInner = nextInner.replace(
|
||||
/(<td[^>]*colspan=")2("[^>]*>\s*<div class="delivery-slip-seal-block")/g,
|
||||
'$13$2'
|
||||
)
|
||||
return `${open}${nextInner}${close}`
|
||||
}
|
||||
)
|
||||
|
||||
result = result.replace(
|
||||
/(<table class="delivery-slip-sign-table"[^>]*>)([\s\S]*?)(<\/table>)/i,
|
||||
(_m, open, inner, close) => `${open}${String(inner).replace(/colspan="7"/g, 'colspan="8"')}${close}`
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 旧版一体 layout-table / 曾拆出的 footer-table → 信息表 + 物料表(含备注条款) + 签字表。
|
||||
*/
|
||||
@@ -1398,6 +1503,7 @@ function migrateDeliverySlipSplitTables(html: string): string {
|
||||
(_full, inner: string) => {
|
||||
const headerMatch =
|
||||
inner.match(/<tr[^>]*class="[^"]*delivery-slip-product-header[^"]*"[\s\S]*?<\/tr>/i) ||
|
||||
inner.match(/<tr>\s*<th[^>]*>单据编号[\s\S]*?<\/tr>/i) ||
|
||||
inner.match(/<tr>\s*<th[^>]*>物料编号[\s\S]*?<\/tr>/i)
|
||||
if (!headerMatch) return _full
|
||||
|
||||
@@ -1510,6 +1616,8 @@ function normalizeDeliverySlipDocLayout(html: string): string {
|
||||
|
||||
if (result.includes('delivery-slip-doc')) {
|
||||
result = result.replace(/<style type="text\/css">[\s\S]*?<\/style>/, DELIVERY_SLIP_STYLE_BLOCK)
|
||||
result = normalizeDeliverySlipInfoLayout(result)
|
||||
result = normalizeDeliverySlipProductPlanNoColumn(result)
|
||||
result = normalizeDeliverySlipSignLabelMarkup(result)
|
||||
result = normalizeDeliverySlipProductGridCell(result)
|
||||
result = normalizeDeliverySlipProductTableFooter(result)
|
||||
@@ -1529,7 +1637,7 @@ function refreshDeliverySlipTypeCheckRowStyle(html: string): string {
|
||||
result = result.replace(
|
||||
/<div class="delivery-slip-type-check-row"[^>]*>([\s\S]*?)<\/div>/,
|
||||
(_match, inner) =>
|
||||
`<div class="delivery-slip-info-row delivery-slip-type-check-wrap" style="${DELIVERY_SLIP_TYPE_CHECK_WRAP_STYLE}"><span class="delivery-slip-info-label delivery-slip-type-check-spacer" style="${INFO_LABEL}visibility:hidden;">单据编号:</span><div class="delivery-slip-type-check-row" style="${DELIVERY_SLIP_TYPE_CHECK_INNER_STYLE}">${inner}</div></div>`
|
||||
`<div class="delivery-slip-info-row delivery-slip-type-check-wrap" style="${DELIVERY_SLIP_TYPE_CHECK_WRAP_STYLE}"><span class="delivery-slip-info-label delivery-slip-type-check-spacer" style="${INFO_LABEL}visibility:hidden;">日 期:</span><div class="delivery-slip-type-check-row" style="${DELIVERY_SLIP_TYPE_CHECK_INNER_STYLE}">${inner}</div></div>`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1537,6 +1645,10 @@ function refreshDeliverySlipTypeCheckRowStyle(html: string): string {
|
||||
/<div class="delivery-slip-info-row delivery-slip-type-check-wrap"[^>]*>/g,
|
||||
`<div class="delivery-slip-info-row delivery-slip-type-check-wrap" style="${DELIVERY_SLIP_TYPE_CHECK_WRAP_STYLE}">`
|
||||
)
|
||||
result = result.replace(
|
||||
/<span class="delivery-slip-info-label delivery-slip-type-check-spacer"[^>]*>[\s\S]*?<\/span>/g,
|
||||
`<span class="delivery-slip-info-label delivery-slip-type-check-spacer" style="${INFO_LABEL}visibility:hidden;">日 期:</span>`
|
||||
)
|
||||
result = result.replace(
|
||||
/<div class="delivery-slip-type-check-row"[^>]*>/g,
|
||||
`<div class="delivery-slip-type-check-row" style="${DELIVERY_SLIP_TYPE_CHECK_INNER_STYLE}">`
|
||||
@@ -1557,12 +1669,26 @@ function normalizeDeliverySlipTypeCheckRow(html: string): string {
|
||||
const checkRowHtml = buildDeliverySlipTypeCheckboxesHtml()
|
||||
|
||||
const withClass = result.replace(
|
||||
/(<td colspan="3"[^>]*style="[^"]*"[^>]*>\s*)(<div class="delivery-slip-info-row"[^>]*>\s*<span class="delivery-slip-info-label"[^>]*>单据编号:)/,
|
||||
/(<td colspan="3"[^>]*style="[^"]*"[^>]*>\s*)(<div class="delivery-slip-info-row"[^>]*>\s*<span class="delivery-slip-info-label"[^>]*>日(?: )?期:)/,
|
||||
`$1${checkRowHtml}\n $2`
|
||||
)
|
||||
if (withClass !== result) {
|
||||
result = withClass
|
||||
} else {
|
||||
result = result.replace(
|
||||
/(<td colspan="3"[^>]*>\s*)(<div class="delivery-slip-info-row"[^>]*>\s*<span class="delivery-slip-info-label"[^>]*>日(?: )?期:)/,
|
||||
`$1${checkRowHtml}\n $2`
|
||||
)
|
||||
}
|
||||
// 兼容旧模板:日期在 colspan=2 单元格时仍插多选
|
||||
if (!result.includes('delivery-slip-type-check-row')) {
|
||||
result = result.replace(
|
||||
/(<td colspan="2"[^>]*>\s*)(<div class="delivery-slip-info-row"[^>]*>\s*<span class="delivery-slip-info-label"[^>]*>日(?: )?期:)/,
|
||||
`$1${checkRowHtml}\n $2`
|
||||
)
|
||||
}
|
||||
// 兼容更旧模板:单据编号位置仍插多选,随后由 infoLayout 迁移
|
||||
if (!result.includes('delivery-slip-type-check-row')) {
|
||||
result = result.replace(
|
||||
/(<td colspan="3"[^>]*>\s*)(<div class="delivery-slip-info-row"[^>]*>\s*<span class="delivery-slip-info-label"[^>]*>单据编号:)/,
|
||||
`$1${checkRowHtml}\n $2`
|
||||
@@ -1673,7 +1799,7 @@ export function replaceDeliverySlipPlaceholders(
|
||||
'{{receiveContact}}': '',
|
||||
'{{driverInfo}}': '',
|
||||
'{{planDateChinese}}': formatPlanDateChinese(plan.planDate),
|
||||
'{{productTable}}': buildProductRows(plan.products, ctx),
|
||||
'{{productTable}}': buildProductRows(plan.products, plan.planNo || '', ctx),
|
||||
'{{remark}}': plan.remark || '',
|
||||
'{{companyAddress}}': DELIVERY_SLIP_DEFAULTS.companyAddress,
|
||||
'{{companyPhone}}': DELIVERY_SLIP_DEFAULTS.companyPhone,
|
||||
@@ -1691,8 +1817,12 @@ export function replaceDeliverySlipPlaceholders(
|
||||
normalizeDeliverySlipProductTableFooter(
|
||||
normalizeDeliverySlipProductColWidths(
|
||||
normalizeDeliverySlipProductGridCell(
|
||||
normalizeDeliverySlipGapBeforeProduct(
|
||||
normalizeDeliverySlipTypeCheckRow(normalizeDeliverySlipSideLabelsPlaceholder(htmlContent))
|
||||
normalizeDeliverySlipProductPlanNoColumn(
|
||||
normalizeDeliverySlipInfoLayout(
|
||||
normalizeDeliverySlipGapBeforeProduct(
|
||||
normalizeDeliverySlipTypeCheckRow(normalizeDeliverySlipSideLabelsPlaceholder(htmlContent))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1732,7 +1862,7 @@ export function restoreDeliverySlipPlaceholders(template: string, plan: Plan): s
|
||||
|
||||
// 产品明细行还原为占位符(表头「实收数量」之后、页脚「备注」之前;兼容分表与旧一体表)
|
||||
result = result.replace(
|
||||
/(<th[^>]*>实收数量<\/th>\s*<\/tr>\s*)([\s\S]*?)(\s*<tr>\s*<td colspan="7"[^>]*>\s*备注:)/,
|
||||
/(<th[^>]*>实收数量<\/th>\s*<\/tr>\s*)([\s\S]*?)(\s*<tr>\s*<td colspan="[78]"[^>]*>\s*备注:)/,
|
||||
'$1{{productTable}}$3'
|
||||
)
|
||||
|
||||
|
||||
@@ -184,6 +184,25 @@ export function getPlPlanTypeLabel(type?: string) {
|
||||
return type ? map[type] || type : '—'
|
||||
}
|
||||
|
||||
/** 打印单据下拉项:入库单 / 送(提)货单 / 分装单 */
|
||||
export type PlPrintSlipCommand = 'inbound' | 'delivery' | 'subpack'
|
||||
|
||||
/**
|
||||
* 按运输计划单据类型返回可打印的单据命令。
|
||||
* - inbound:仅入库单
|
||||
* - outbound:送(提)货单、分装单
|
||||
* - direct / 其他:不可打印
|
||||
*/
|
||||
export function getPrintableSlipCommands(planType?: string): PlPrintSlipCommand[] {
|
||||
if (planType === 'inbound') return ['inbound']
|
||||
if (planType === 'outbound') return ['delivery', 'subpack']
|
||||
return []
|
||||
}
|
||||
|
||||
export function canPrintSlipCommand(planType: string | undefined, command: PlPrintSlipCommand) {
|
||||
return getPrintableSlipCommands(planType).includes(command)
|
||||
}
|
||||
|
||||
export type PlPlanTypeTab = 'all' | 'inbound' | 'outbound' | 'direct'
|
||||
|
||||
export const PL_PLAN_TYPE_TABS: { label: string; name: PlPlanTypeTab }[] = [
|
||||
|
||||
Reference in new issue
Block a user