feat(web-admin): add mp plan form anchors and polish print customer pick.
Improve the page-variant plan form for WebView and align print customer selection with the mobile demo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
bf81d9b77c
commit
ca0098f6ca
2 files changed
+163
-23
No files matched your search
@@ -8,8 +8,20 @@
|
||||
@update:model-value="onFormShellVisible"
|
||||
>
|
||||
<h2 v-if="isPageVariant" class="mp-plan-form-title">{{ dialogTitle }}</h2>
|
||||
<nav v-if="isPageVariant" class="mp-plan-anchor-bar">
|
||||
<button
|
||||
v-for="item in mpAnchors"
|
||||
:key="item.id"
|
||||
type="button"
|
||||
class="mp-plan-anchor"
|
||||
:class="{ active: mpActiveAnchor === item.id }"
|
||||
@click="scrollMpAnchor(item.id)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</button>
|
||||
</nav>
|
||||
<div class="pl-plan-form-body">
|
||||
<section class="pl-plan-form-section">
|
||||
<section id="sec-basic" class="pl-plan-form-section">
|
||||
<h3 class="pl-plan-form-section-title">基础信息</h3>
|
||||
<el-form
|
||||
ref="basicFormRef"
|
||||
@@ -66,7 +78,7 @@
|
||||
</el-form>
|
||||
</section>
|
||||
|
||||
<section class="pl-plan-form-section">
|
||||
<section id="sec-transport" class="pl-plan-form-section">
|
||||
<h3 class="pl-plan-form-section-title">运输信息</h3>
|
||||
<el-form
|
||||
:model="formData"
|
||||
@@ -190,8 +202,9 @@
|
||||
</el-form>
|
||||
</section>
|
||||
|
||||
<section class="pl-plan-form-section">
|
||||
<section id="sec-load" class="pl-plan-form-section">
|
||||
<h3 class="pl-plan-form-section-title">装送货信息</h3>
|
||||
<div id="sec-delivery" class="mp-plan-anchor-target" aria-hidden="true" />
|
||||
<el-form :label-position="formLabelPosition" label-width="100px" class="pl-dialog-form">
|
||||
<PlPlanStopsSplitShell
|
||||
:plan-total-qty="planTotalQty"
|
||||
@@ -261,7 +274,7 @@
|
||||
</el-form>
|
||||
</section>
|
||||
|
||||
<section class="pl-plan-form-section">
|
||||
<section id="sec-remark" class="pl-plan-form-section">
|
||||
<h3 class="pl-plan-form-section-title">备注</h3>
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||
</section>
|
||||
@@ -302,7 +315,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="mp-plan-form-footer dialog-footer">
|
||||
<div v-if="isPageVariant" class="mp-plan-form-footer dialog-footer">
|
||||
<el-button @click="handleCancel">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
@@ -541,6 +554,19 @@
|
||||
const isCopy = computed(() => !props.planId && !!props.copyFromPlanId)
|
||||
const isPageVariant = computed(() => props.variant === 'page')
|
||||
const formLabelPosition = computed(() => (isPageVariant.value ? 'top' : 'right'))
|
||||
const mpAnchors = [
|
||||
{ id: 'sec-basic', label: '基础' },
|
||||
{ id: 'sec-transport', label: '运输' },
|
||||
{ id: 'sec-load', label: '装货' },
|
||||
{ id: 'sec-delivery', label: '送货' },
|
||||
{ id: 'sec-remark', label: '备注' }
|
||||
]
|
||||
const mpActiveAnchor = ref('sec-basic')
|
||||
|
||||
function scrollMpAnchor(id: string) {
|
||||
mpActiveAnchor.value = id
|
||||
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
const dialogTitle = computed(() => (isEdit.value ? '编辑运输计划' : '新增运输计划'))
|
||||
|
||||
const innerVisible = computed({
|
||||
@@ -2406,6 +2432,39 @@
|
||||
color: #087f57;
|
||||
}
|
||||
|
||||
.mp-plan-anchor-bar {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 0 0 12px;
|
||||
padding-bottom: 2px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.mp-plan-anchor {
|
||||
flex: 0 0 auto;
|
||||
height: 30px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #dcebe4;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
color: #6b7b74;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mp-plan-anchor.active {
|
||||
color: #fff;
|
||||
background: #0a9f6d;
|
||||
border-color: #0a9f6d;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mp-plan-anchor-target {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mp-plan-form-page {
|
||||
:deep(.form-grid-5),
|
||||
:deep(.form-grid-4),
|
||||
@@ -2440,8 +2499,10 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding: 12px 0 calc(8px + env(safe-area-inset-bottom));
|
||||
background: #f5f8f7;
|
||||
margin: 0 -4px;
|
||||
padding: 10px 4px calc(10px + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
border-top: 1px solid #dcebe4;
|
||||
}
|
||||
|
||||
.pl-plan-transport-row {
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
<button class="mp-wv-header__back" type="button" @click="goBack">← 详情</button>
|
||||
</div>
|
||||
<h1>打印单据</h1>
|
||||
<div class="mp-wv-header__sub">长按预览区可存图(WebView 不支持系统打印)</div>
|
||||
</header>
|
||||
|
||||
<p class="mp-print-hint">长按预览区可保存图片;WebView 不支持系统打印。</p>
|
||||
<p class="mp-print-hint">WebView 不调用系统打印机,引导长按存图。</p>
|
||||
|
||||
<div class="mp-wv-chips">
|
||||
<button
|
||||
@@ -25,33 +26,50 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="kind === 'delivery' && customers.length > 1" class="mp-wv-toolbar">
|
||||
<el-select
|
||||
v-model="customerId"
|
||||
placeholder="选择送货客户"
|
||||
style="width: 100%"
|
||||
@change="reloadPreview"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in customers"
|
||||
:key="item.customerId"
|
||||
:label="item.customerName"
|
||||
:value="item.customerId"
|
||||
/>
|
||||
</el-select>
|
||||
<div v-if="needCustomer" class="mp-wv-section" style="margin-top: 0">
|
||||
<h3>送货客户</h3>
|
||||
<button class="mp-wv-picker" type="button" @click="customerSheetOpen = true">
|
||||
<span :class="{ 'is-ph': !customerLabel }">{{ customerLabel || '请选择送货客户' }}</span>
|
||||
<span class="mp-wv-picker__chev">选择</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="mp-wv-empty">正在生成单据…</div>
|
||||
<div v-else-if="blockReason" class="mp-wv-empty">{{ blockReason }}</div>
|
||||
<div v-else class="mp-print-preview" v-html="html"></div>
|
||||
|
||||
<div class="mp-wv-fab-bar">
|
||||
<button class="mp-wv-btn" type="button" @click="goBack">返回详情</button>
|
||||
<button class="mp-wv-btn mp-wv-btn--primary" type="button" @click="hintSave">
|
||||
保存预览
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<MpBottomSheet v-model="customerSheetOpen" title="选择送货客户" searchable search-placeholder="搜索客户">
|
||||
<template #default="{ keyword }">
|
||||
<button
|
||||
v-for="item in filteredCustomers(keyword)"
|
||||
:key="item.customerId"
|
||||
class="mp-wv-filter-opt"
|
||||
type="button"
|
||||
@click="pickCustomer(item)"
|
||||
>
|
||||
<span>{{ item.customerName }}</span>
|
||||
<span v-if="item.customerId === customerId">✓</span>
|
||||
</button>
|
||||
<div v-if="!filteredCustomers(keyword).length" class="mp-wv-empty">无匹配客户</div>
|
||||
</template>
|
||||
</MpBottomSheet>
|
||||
</template>
|
||||
</MpWebviewShell>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import MpWebviewShell from '@/layouts/MpWebviewShell.vue'
|
||||
import MpBottomSheet from '@/components/mp/MpBottomSheet.vue'
|
||||
import { planApi, type Plan } from '@/api/pl'
|
||||
import { canBatchPrintSlip } from '@/utils/pl-batch-print'
|
||||
import { listDeliveryPrintCustomers } from '@/utils/pl-delivery-slip-print'
|
||||
@@ -80,6 +98,20 @@
|
||||
const blockReason = ref('')
|
||||
const customerId = ref('')
|
||||
const customers = ref<{ customerId: string; customerName: string }[]>([])
|
||||
const customerSheetOpen = ref(false)
|
||||
|
||||
const needCustomer = computed(
|
||||
() => kind.value === 'delivery' || kind.value === 'blank-delivery'
|
||||
)
|
||||
const customerLabel = computed(
|
||||
() => customers.value.find((c) => c.customerId === customerId.value)?.customerName || ''
|
||||
)
|
||||
|
||||
function filteredCustomers(keyword: string) {
|
||||
const kw = (keyword || '').trim().toLowerCase()
|
||||
if (!kw) return customers.value
|
||||
return customers.value.filter((c) => c.customerName.toLowerCase().includes(kw))
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
if (window.history.length > 1) {
|
||||
@@ -90,6 +122,10 @@
|
||||
void router.replace(id ? `/m/pl/plan/${id}` : '/m/pl/plan')
|
||||
}
|
||||
|
||||
function hintSave() {
|
||||
ElMessage.info('请长按预览区保存图片')
|
||||
}
|
||||
|
||||
function slipCommand(current: MpPlanPrintKind) {
|
||||
if (current === 'inbound' || current === 'delivery' || current === 'subpack') return current
|
||||
return null
|
||||
@@ -97,6 +133,11 @@
|
||||
|
||||
async function reloadPreview() {
|
||||
const current = kind.value
|
||||
if (needCustomer.value && !customerId.value) {
|
||||
html.value = ''
|
||||
blockReason.value = '请先选择送货客户'
|
||||
return
|
||||
}
|
||||
const command = slipCommand(current)
|
||||
if (command && plan.value) {
|
||||
const check = canBatchPrintSlip([plan.value], command)
|
||||
@@ -125,6 +166,12 @@
|
||||
void reloadPreview()
|
||||
}
|
||||
|
||||
function pickCustomer(item: { customerId: string; customerName: string }) {
|
||||
customerId.value = item.customerId
|
||||
customerSheetOpen.value = false
|
||||
void reloadPreview()
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const id = String(route.params.id || '')
|
||||
if (!id) {
|
||||
@@ -146,3 +193,35 @@
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mp-wv-header__sub {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.mp-wv-picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #dcebe4;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
color: #1f2a26;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mp-wv-picker .is-ph {
|
||||
color: #6b7b74;
|
||||
}
|
||||
|
||||
.mp-wv-picker__chev {
|
||||
color: #0a9f6d;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user