feat(web-admin): 出入库现场页支持选择单据状态并作废只读
提交携带 status;作废需确认;作废后整页只读可查看。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
1df9bbe22a
commit
dee85f182e
1 file changed
+51
-3
@@ -5,8 +5,14 @@
|
||||
|
||||
<van-loading v-if="loading" vertical class="page-loading">加载中...</van-loading>
|
||||
<van-empty v-else-if="errorMessage" :description="errorMessage" />
|
||||
<van-empty v-else-if="page?.voided" description="单据已作废" />
|
||||
<template v-else-if="page">
|
||||
<van-notice-bar
|
||||
v-if="isReadOnly"
|
||||
left-icon="info-o"
|
||||
color="#92400e"
|
||||
background="#fffbeb"
|
||||
text="单据已作废,仅可查看"
|
||||
/>
|
||||
<van-cell-group inset class="section-card">
|
||||
<van-cell title="业务类型" :value="page.businessType || '—'" />
|
||||
<van-cell title="日期" :value="page.planDate || '—'" />
|
||||
@@ -105,6 +111,7 @@
|
||||
class="actual-box__field"
|
||||
placeholder="请输入"
|
||||
:border="false"
|
||||
:readonly="isReadOnly"
|
||||
/>
|
||||
<span class="actual-box__unit">{{ item.unit || '吨' }}</span>
|
||||
</div>
|
||||
@@ -118,12 +125,24 @@
|
||||
v-model="uploaderFiles"
|
||||
multiple
|
||||
:max-count="9"
|
||||
:deletable="!isReadOnly"
|
||||
:show-upload="!isReadOnly"
|
||||
:after-read="handleAfterRead"
|
||||
:before-delete="handleBeforeDelete"
|
||||
/>
|
||||
</div>
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group v-if="!isReadOnly" inset class="section-card" title="单据状态">
|
||||
<div class="status-radio-wrap">
|
||||
<van-radio-group v-model="selectedStatus" direction="horizontal">
|
||||
<van-radio name="in_progress">进行中</van-radio>
|
||||
<van-radio name="completed">已完成</van-radio>
|
||||
<van-radio name="voided">已作废</van-radio>
|
||||
</van-radio-group>
|
||||
</div>
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group inset class="section-card" title="现场备注">
|
||||
<van-field
|
||||
v-model="feedbackRemark"
|
||||
@@ -133,6 +152,7 @@
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="填写现场备注"
|
||||
:readonly="isReadOnly"
|
||||
/>
|
||||
</van-cell-group>
|
||||
|
||||
@@ -140,7 +160,7 @@
|
||||
<van-cell title="上次保存" :value="formatDateTime(page.siteFeedbackTime)" />
|
||||
</van-cell-group>
|
||||
|
||||
<footer class="page-footer">
|
||||
<footer v-if="!isReadOnly" class="page-footer">
|
||||
<van-button type="primary" block round :loading="saving" @click="handleSave">
|
||||
提交
|
||||
</van-button>
|
||||
@@ -152,7 +172,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { UploaderFileListItem } from 'vant'
|
||||
import { showFailToast, showSuccessToast } from 'vant'
|
||||
import { showConfirmDialog, showFailToast, showSuccessToast } from 'vant'
|
||||
import {
|
||||
createPublicIoOrderApi,
|
||||
type PublicIoOrderItem,
|
||||
@@ -161,9 +181,12 @@
|
||||
import PublicMobileShell from '@/layouts/PublicMobileShell.vue'
|
||||
import { buildAmapNavigationUrl } from '@/utils/amap/navigation'
|
||||
|
||||
import 'vant/es/dialog/style'
|
||||
import 'vant/es/toast/style'
|
||||
import '@/styles/public-mobile-vant.scss'
|
||||
|
||||
type IoOrderStatus = 'in_progress' | 'completed' | 'voided'
|
||||
|
||||
const props = defineProps<{ kind: 'inbound' | 'outbound' }>()
|
||||
const api = createPublicIoOrderApi(props.kind)
|
||||
const route = useRoute()
|
||||
@@ -180,6 +203,8 @@
|
||||
const feedbackImages = ref<string[]>([])
|
||||
const uploaderFiles = ref<UploaderFileListItem[]>([])
|
||||
const editableItems = ref<(PublicIoOrderItem & { actualQtyText: string })[]>([])
|
||||
const selectedStatus = ref<IoOrderStatus>('in_progress')
|
||||
const isReadOnly = computed(() => Boolean(page.value?.voided))
|
||||
|
||||
const deliveryAddressDisplay = computed(() => {
|
||||
if (!page.value) return '—'
|
||||
@@ -258,6 +283,11 @@
|
||||
...it,
|
||||
actualQtyText: it.actualQty != null ? String(it.actualQty) : ''
|
||||
}))
|
||||
selectedStatus.value = (
|
||||
['in_progress', 'completed', 'voided'].includes(data.status || '')
|
||||
? data.status
|
||||
: 'in_progress'
|
||||
) as IoOrderStatus
|
||||
syncUploaderFromImages()
|
||||
} catch (e: any) {
|
||||
errorMessage.value = e?.message || '链接无效或已失效'
|
||||
@@ -268,6 +298,7 @@
|
||||
}
|
||||
|
||||
async function handleAfterRead(item: UploaderFileListItem | UploaderFileListItem[]) {
|
||||
if (isReadOnly.value) return
|
||||
const files = Array.isArray(item) ? item : [item]
|
||||
for (const fileItem of files) {
|
||||
if (!fileItem.file) continue
|
||||
@@ -290,6 +321,7 @@
|
||||
}
|
||||
|
||||
function handleBeforeDelete(item: UploaderFileListItem) {
|
||||
if (isReadOnly.value) return false
|
||||
const fileUrl = (item as UploaderFileListItem & { fileUrl?: string }).fileUrl
|
||||
if (fileUrl) {
|
||||
feedbackImages.value = feedbackImages.value.filter(u => u !== fileUrl)
|
||||
@@ -298,9 +330,21 @@
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (isReadOnly.value) return
|
||||
if (selectedStatus.value === 'voided') {
|
||||
try {
|
||||
await showConfirmDialog({
|
||||
title: '确认作废',
|
||||
message: '确认作废本出入库单?作废后不可再提交。'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
await api.saveFeedback(token.value, {
|
||||
status: selectedStatus.value,
|
||||
remark: feedbackRemark.value,
|
||||
images: feedbackImages.value,
|
||||
items: editableItems.value.map(it => ({
|
||||
@@ -350,6 +394,10 @@
|
||||
padding: 8px 14px 12px;
|
||||
}
|
||||
|
||||
.status-radio-wrap {
|
||||
padding: 12px 16px 16px;
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user