This commit is contained in:
zlwu committed 2026-09-02 08:20:52 +08:00
1 parent 506cc7991a
commit 1dfcc66d2c
269 files changed
+1413333 -55990

No files matched your search

@@ -2,7 +2,6 @@
<template>
<el-dialog
v-model="visible"
:title="isPreviewMode ? '预览送(提)货单' : '编辑送(提)货单'"
width="1500px"
align-center
append-to-body
@@ -12,6 +11,24 @@
:close-on-click-modal="false"
@closed="handleClosed"
>
<template #header>
<div class="pl-slip-print-dialog-header">
<span class="pl-slip-print-dialog-title">{{ isPreviewMode ? '预览送(提)货单' : '编辑送(提)货单' }}</span>
<el-radio-group
v-model="selectedCompanyKey"
class="pl-slip-company-radio"
@change="handleCompanyChange"
>
<el-radio
v-for="item in PL_SLIP_COMPANY_OPTIONS"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</el-radio>
</el-radio-group>
</div>
</template>
<TinyMceEditor
v-model="slipContent"
:height="editorHeight"
@@ -76,6 +93,11 @@ import {
type DeliverySlipRenderContext
} from '@/utils/pl-delivery-slip-template'
import { buildBatchPrintPlanView, normalizePlanIds } from '@/utils/pl-batch-print'
import {
applyPlSlipCompanyToHtml,
PL_SLIP_COMPANY_OPTIONS,
type PlSlipCompanyKey
} from '@/utils/pl-slip-company'
import { injectSlipSealImages, stripSlipSealImages } from '@/utils/pl-slip-red-seal'
import { getPlSlipPdfCanvasScale } from '@/utils/pl-slip-pdf-render'
@@ -85,6 +107,7 @@ const isPreviewMode = ref(false)
const isBlankMode = ref(false)
/** 打印弹窗内红章显隐(仅本次弹窗有效,打开时默认显示) */
const showRedSeal = ref(true)
const selectedCompanyKey = ref<PlSlipCompanyKey>('shanxia')
const saveLoading = ref(false)
const pdfGenerating = ref(false)
const currentPlanId = ref('')
@@ -95,6 +118,10 @@ const editorHeight = computed(() => {
return Math.min(860, Math.max(720, window.innerHeight - 200))
})
function handleCompanyChange(key: PlSlipCompanyKey) {
slipContent.value = applyPlSlipCompanyToHtml(slipContent.value, key, { swapSeal: true })
}
async function waitForImagesLoaded(container: HTMLElement) {
const imgs = Array.from(container.querySelectorAll('img'))
await Promise.all(
@@ -150,6 +177,7 @@ function openBlank() {
isBlankMode.value = true
isPreviewMode.value = false
showRedSeal.value = false
selectedCompanyKey.value = 'shanxia'
slipContent.value = renderBlankDeliverySlipHtml()
visible.value = true
}
@@ -164,6 +192,7 @@ async function open(planIdOrIds: string | string[], options?: { customerId?: str
isBlankMode.value = false
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
try {
ElMessage.info({
message: ids.length > 1 ? '正在生成合打送(提)货单...' : '正在生成送(提)货单...',
@@ -212,6 +241,7 @@ function handleClosed() {
isBlankMode.value = false
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
}
/** 切换红章显示/隐藏(同步影响编辑器、打印、PDF) */
@@ -223,7 +253,7 @@ function toggleRedSeal() {
}
slipContent.value = injectSlipSealImages(
slipContent.value,
buildDeliverySlipCompanySealHtml(),
buildDeliverySlipCompanySealHtml(selectedCompanyKey.value),
'delivery-slip-seal-block'
)
showRedSeal.value = true
@@ -246,7 +276,9 @@ async function handleSaveTemplate() {
try {
const plan = (await refreshPlan()) || currentPlan.value
if (!plan) throw new Error('计划数据无效')
const finalTemplate = restoreDeliverySlipPlaceholders(slipContent.value, plan)
// 保存前归一为山峡抬头与山峡红章,避免把云栋切换态写入模板
const normalized = applyPlSlipCompanyToHtml(slipContent.value, 'shanxia', { swapSeal: true })
const finalTemplate = restoreDeliverySlipPlaceholders(normalized, plan)
await planApi.saveDeliverySlipTemplate(currentPlanId.value, finalTemplate)
ElMessage.success('模板保存成功')
} catch (error) {
@@ -305,6 +337,7 @@ async function handleGeneratePdf() {
if (plan) {
const renderCtx = await buildSlipRenderContext(plan)
htmlContent = replaceDeliverySlipPlaceholders(htmlContent, plan, renderCtx)
htmlContent = applyPlSlipCompanyToHtml(htmlContent, selectedCompanyKey.value, { swapSeal: true })
}
}
@@ -377,6 +410,38 @@ defineExpose({ open, openBlank })
</script>
<style scoped lang="scss">
.pl-slip-print-dialog-header {
position: relative;
display: flex;
align-items: center;
width: 100%;
min-height: 24px;
padding-right: 28px;
box-sizing: border-box;
}
.pl-slip-print-dialog-title {
position: relative;
z-index: 1;
flex-shrink: 0;
font-size: 18px;
font-weight: 600;
line-height: 24px;
color: var(--el-text-color-primary);
}
.pl-slip-company-radio {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: inline-flex;
flex-wrap: wrap;
gap: 8px 20px;
justify-content: center;
max-width: calc(100% - 280px);
}
.delivery-slip-print-actions {
display: flex;
flex-wrap: wrap;
@@ -2,7 +2,6 @@
<template>
<el-dialog
v-model="visible"
:title="isPreviewMode ? '预览入库单' : '编辑入库单'"
width="1500px"
align-center
append-to-body
@@ -12,6 +11,24 @@
:close-on-click-modal="false"
@closed="handleClosed"
>
<template #header>
<div class="pl-slip-print-dialog-header">
<span class="pl-slip-print-dialog-title">{{ isPreviewMode ? '预览入库单' : '编辑入库单' }}</span>
<el-radio-group
v-model="selectedCompanyKey"
class="pl-slip-company-radio"
@change="handleCompanyChange"
>
<el-radio
v-for="item in PL_SLIP_COMPANY_OPTIONS"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</el-radio>
</el-radio-group>
</div>
</template>
<TinyMceEditor
v-model="slipContent"
:height="editorHeight"
@@ -74,6 +91,11 @@ import {
type InboundSlipRenderContext
} from '@/utils/pl-inbound-slip-template'
import { buildBatchPrintPlanView, normalizePlanIds } from '@/utils/pl-batch-print'
import {
applyPlSlipCompanyToHtml,
PL_SLIP_COMPANY_OPTIONS,
type PlSlipCompanyKey
} from '@/utils/pl-slip-company'
import { injectSlipSealImages, stripSlipSealImages } from '@/utils/pl-slip-red-seal'
import { getPlSlipPdfCanvasScale } from '@/utils/pl-slip-pdf-render'
@@ -83,6 +105,7 @@ const isPreviewMode = ref(false)
const isBlankMode = ref(false)
/** 打印弹窗内红章显隐(仅本次弹窗有效,打开时默认显示) */
const showRedSeal = ref(true)
const selectedCompanyKey = ref<PlSlipCompanyKey>('shanxia')
const saveLoading = ref(false)
const pdfGenerating = ref(false)
const currentPlanId = ref('')
@@ -93,6 +116,10 @@ const editorHeight = computed(() => {
return Math.min(860, Math.max(720, window.innerHeight - 200))
})
function handleCompanyChange(key: PlSlipCompanyKey) {
slipContent.value = applyPlSlipCompanyToHtml(slipContent.value, key)
}
async function waitForImagesLoaded(container: HTMLElement) {
const imgs = Array.from(container.querySelectorAll('img'))
await Promise.all(
@@ -148,6 +175,7 @@ function openBlank() {
isBlankMode.value = true
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
slipContent.value = renderBlankInboundSlipHtml()
visible.value = true
}
@@ -162,6 +190,7 @@ async function open(planIdOrIds: string | string[]) {
isBlankMode.value = false
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
try {
ElMessage.info({ message: ids.length > 1 ? '正在生成合打入库单...' : '正在生成入库单...', duration: 800 })
const plans = await Promise.all(
@@ -202,6 +231,7 @@ function handleClosed() {
isBlankMode.value = false
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
}
/** 切换红章显示/隐藏(同步影响编辑器、打印、PDF) */
@@ -236,7 +266,9 @@ async function handleSaveTemplate() {
try {
const plan = (await refreshPlan()) || currentPlan.value
if (!plan) throw new Error('计划数据无效')
const finalTemplate = restoreInboundSlipPlaceholders(slipContent.value, plan)
// 保存前归一为山峡抬头,避免把云栋切换态写入模板
const normalized = applyPlSlipCompanyToHtml(slipContent.value, 'shanxia')
const finalTemplate = restoreInboundSlipPlaceholders(normalized, plan)
await planApi.saveInboundSlipTemplate(currentPlanId.value, finalTemplate)
ElMessage.success('模板保存成功')
} catch (error) {
@@ -295,6 +327,7 @@ async function handleGeneratePdf() {
if (plan) {
const renderCtx = await buildSlipRenderContext(plan)
htmlContent = replaceInboundSlipPlaceholders(htmlContent, plan, renderCtx)
htmlContent = applyPlSlipCompanyToHtml(htmlContent, selectedCompanyKey.value)
}
}
@@ -367,6 +400,38 @@ defineExpose({ open, openBlank })
</script>
<style scoped lang="scss">
.pl-slip-print-dialog-header {
position: relative;
display: flex;
align-items: center;
width: 100%;
min-height: 24px;
padding-right: 28px;
box-sizing: border-box;
}
.pl-slip-print-dialog-title {
position: relative;
z-index: 1;
flex-shrink: 0;
font-size: 18px;
font-weight: 600;
line-height: 24px;
color: var(--el-text-color-primary);
}
.pl-slip-company-radio {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: inline-flex;
flex-wrap: wrap;
gap: 8px 20px;
justify-content: center;
max-width: calc(100% - 280px);
}
.inbound-slip-print-actions {
display: flex;
flex-wrap: wrap;
@@ -2,7 +2,6 @@
<template>
<el-dialog
v-model="visible"
:title="isPreviewMode ? '预览分装单' : '编辑分装单'"
width="1500px"
align-center
append-to-body
@@ -12,6 +11,24 @@
:close-on-click-modal="false"
@closed="handleClosed"
>
<template #header>
<div class="pl-slip-print-dialog-header">
<span class="pl-slip-print-dialog-title">{{ isPreviewMode ? '预览分装单' : '编辑分装单' }}</span>
<el-radio-group
v-model="selectedCompanyKey"
class="pl-slip-company-radio"
@change="handleCompanyChange"
>
<el-radio
v-for="item in PL_SLIP_COMPANY_OPTIONS"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</el-radio>
</el-radio-group>
</div>
</template>
<TinyMceEditor
v-model="slipContent"
:height="editorHeight"
@@ -77,6 +94,11 @@ import {
type SubpackSlipRenderContext
} from '@/utils/pl-subpack-slip-template'
import { buildBatchPrintPlanView, normalizePlanIds } from '@/utils/pl-batch-print'
import {
applyPlSlipCompanyToHtml,
PL_SLIP_COMPANY_OPTIONS,
type PlSlipCompanyKey
} from '@/utils/pl-slip-company'
import { injectSlipSealImages, stripSlipSealImages } from '@/utils/pl-slip-red-seal'
import { getPlSlipPdfCanvasScale } from '@/utils/pl-slip-pdf-render'
@@ -86,6 +108,7 @@ const isPreviewMode = ref(false)
const isBlankMode = ref(false)
/** 打印弹窗内红章显隐(仅本次弹窗有效,打开时默认显示) */
const showRedSeal = ref(true)
const selectedCompanyKey = ref<PlSlipCompanyKey>('shanxia')
const saveLoading = ref(false)
const pdfGenerating = ref(false)
const currentPlanId = ref('')
@@ -97,6 +120,10 @@ const editorHeight = computed(() => {
return Math.min(860, Math.max(720, window.innerHeight - 200))
})
function handleCompanyChange(key: PlSlipCompanyKey) {
slipContent.value = applyPlSlipCompanyToHtml(slipContent.value, key)
}
async function waitForImagesLoaded(container: HTMLElement) {
const imgs = Array.from(container.querySelectorAll('img'))
await Promise.all(
@@ -142,6 +169,7 @@ function openBlank() {
isBlankMode.value = true
isPreviewMode.value = false
showRedSeal.value = false
selectedCompanyKey.value = 'shanxia'
slipContent.value = renderBlankSubpackSlipHtml()
visible.value = true
}
@@ -156,6 +184,7 @@ async function open(planIdOrIds: string | string[]) {
isBlankMode.value = false
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
try {
ElMessage.info({ message: ids.length > 1 ? '正在生成合打分装单...' : '正在生成分装单...', duration: 800 })
const plans = await Promise.all(
@@ -202,6 +231,7 @@ function handleClosed() {
isBlankMode.value = false
isPreviewMode.value = false
showRedSeal.value = true
selectedCompanyKey.value = 'shanxia'
}
/** 切换红章显示/隐藏(同步影响编辑器、打印、PDF) */
@@ -238,7 +268,9 @@ async function handleSaveTemplate() {
try {
const plan = (await refreshPlan()) || currentPlan.value
if (!plan) throw new Error('计划数据无效')
const finalTemplate = restoreSubpackSlipPlaceholders(slipContent.value, plan)
// 保存前归一为山峡抬头,避免把云栋切换态写入模板
const normalized = applyPlSlipCompanyToHtml(slipContent.value, 'shanxia')
const finalTemplate = restoreSubpackSlipPlaceholders(normalized, plan)
await planApi.saveSubpackSlipTemplate(currentPlanId.value, finalTemplate)
ElMessage.success('模板保存成功')
} catch (error) {
@@ -297,6 +329,7 @@ async function handleGeneratePdf() {
if (plan) {
const renderCtx = await buildSlipRenderContext(plan)
htmlContent = replaceSubpackSlipPlaceholders(htmlContent, plan, renderCtx)
htmlContent = applyPlSlipCompanyToHtml(htmlContent, selectedCompanyKey.value)
}
}
@@ -369,6 +402,38 @@ defineExpose({ open, openBlank })
</script>
<style scoped lang="scss">
.pl-slip-print-dialog-header {
position: relative;
display: flex;
align-items: center;
width: 100%;
min-height: 24px;
padding-right: 28px;
box-sizing: border-box;
}
.pl-slip-print-dialog-title {
position: relative;
z-index: 1;
flex-shrink: 0;
font-size: 18px;
font-weight: 600;
line-height: 24px;
color: var(--el-text-color-primary);
}
.pl-slip-company-radio {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: inline-flex;
flex-wrap: wrap;
gap: 8px 20px;
justify-content: center;
max-width: calc(100% - 280px);
}
.subpack-slip-print-actions {
display: flex;
flex-wrap: wrap;