优化
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import '@/styles/adminWorkbench.css'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox, type UploadFile } from 'element-plus'
|
||||
import { createPlatformExportTask } from '@/modules/downloads'
|
||||
@@ -295,7 +296,7 @@ onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="container-customs surface-panel admin-density" aria-label="整柜报关">
|
||||
<section class="container-customs surface-panel admin-density admin-workbench" aria-label="整柜报关">
|
||||
<OperationErrorToast :details="actionError" />
|
||||
<header class="customs-header">
|
||||
<div><h2>整柜报关</h2></div>
|
||||
@@ -323,11 +324,11 @@ onMounted(load)
|
||||
</dl>
|
||||
<div v-if="missingInbounds.length" class="compact-table-wrap">
|
||||
<h3>缺退税资料清单</h3>
|
||||
<table class="compact-table density-table"><thead><tr><th>客户</th><th>订单号</th><th>入仓码</th></tr></thead><tbody><tr v-for="item in missingInbounds" :key="item.inboundId"><td>{{ item.customerName }}</td><td>{{ item.orderNo }}</td><td>{{ item.inboundCode }}</td></tr></tbody></table>
|
||||
<div class="workbench-evidence"><table class="compact-table density-table"><thead><tr><th>客户</th><th>订单号</th><th>入仓码</th></tr></thead><tbody><tr v-for="item in missingInbounds" :key="item.inboundId"><td>{{ item.customerName }}</td><td>{{ item.orderNo }}</td><td>{{ item.inboundCode }}</td></tr></tbody></table></div>
|
||||
</div>
|
||||
<div v-if="customs.documents.length" class="compact-table-wrap">
|
||||
<h3>已冻结退税资料、报关行回执与完税文件</h3>
|
||||
<table class="compact-table document-table density-table"><thead><tr><th>操作</th><th>客户退税资料</th><th>报关行回执</th><th>真实报关完税文件</th><th>关联入仓码</th><th>报关行状态</th><th>版本</th><th>客户</th><th>回执情况</th></tr></thead><tbody>
|
||||
<div class="workbench-evidence"><table class="compact-table document-table density-table"><thead><tr><th>操作</th><th>客户退税资料</th><th>报关行回执</th><th>真实报关完税文件</th><th>关联入仓码</th><th>报关行状态</th><th>版本</th><th>客户</th><th>回执情况</th></tr></thead><tbody>
|
||||
<tr v-for="document in customs.documents" :key="document.documentId">
|
||||
<td><div v-if="canManage && customs.status === 'DECLARING'" class="document-actions density-actions"><el-upload :disabled="!brokerSubmission || brokerSubmitted" :auto-upload="false" :limit="1" :show-file-list="false" :on-change="(upload: UploadFile) => selectReceipt(document.documentId, upload)"><el-button class="density-action" size="small" :disabled="!brokerSubmission || brokerSubmitted">{{ !brokerSubmission ? '首次发送后上传回执' : document.receipt ? '覆盖报关行回执' : '上传报关行回执' }}</el-button></el-upload><el-button data-tone="primary" class="density-action" size="small" type="primary" :disabled="!brokerSubmission || brokerSubmitted || !receiptFiles[document.documentId]" :loading="actionLoading" @click="uploadReceipt(document)">提交</el-button><el-upload :disabled="!brokerSubmitted" :auto-upload="false" :limit="1" :show-file-list="false" :on-change="(upload: UploadFile) => selectFinal(document.documentId, upload)"><el-button class="density-action" size="small" :disabled="!brokerSubmitted">{{ document.finalDocument ? '覆盖完税文件' : '上传完税文件' }}</el-button></el-upload><el-button data-tone="primary" class="density-action" size="small" type="primary" :disabled="!brokerSubmitted || !finalFiles[document.documentId]" :loading="actionLoading" @click="uploadFinal(document)">提交</el-button></div><span v-else class="readonly-label">只读</span></td>
|
||||
<td><div class="file-cell"><span :title="document.source.fileName">{{ document.source.fileName }}</span><el-button class="density-action" type="primary" :loading="downloadingKey === `source:${document.documentId}`" :aria-label="`下载客户退税资料 ${document.source.fileName}`" @click="downloadFile(document, 'source')">下载</el-button></div></td>
|
||||
@@ -335,7 +336,7 @@ onMounted(load)
|
||||
<td><div v-if="document.finalDocument" class="file-cell"><span :title="document.finalDocument.fileName">{{ document.finalDocument.fileName }}</span><el-button class="density-action" type="primary" :loading="downloadingKey === `final:${document.documentId}`" :aria-label="`下载报关完税文件 ${document.finalDocument.fileName}`" @click="downloadFile(document, 'final')">下载</el-button></div><span v-else>未上传</span></td>
|
||||
<td>{{ document.inboundCodes.join('、') || '—' }}</td><td>{{ brokerSubmitted ? '已发送报关行执行' : brokerSubmission ? '已首次发送,等待回执确认' : '待首次发送报关行' }}</td><td>退税资料 v{{ document.source.version }}<span v-if="document.receipt"> / 回执 v{{ document.receipt.version }}</span><span v-if="document.finalDocument"> / 完税 v{{ document.finalDocument.version }}</span><small v-if="document.receiptHistory?.length" class="receipt-history-note">回执历史:{{ receiptHistoryLabel(document) }}</small><small v-for="history in document.confirmationHistory" :key="history.id" class="confirmation-history-note">{{ confirmationActionLabel(history.action) }} · {{ formatDateTime(history.createdAt) }} · {{ history.operatorName || '—' }}<span v-if="history.reason"> · {{ history.reason }}</span></small></td><td>{{ documentCustomers(document) }}</td><td>{{ document.receipt ? (document.receiptStatus === 'CONFIRMED' ? '客户已确认回执' : document.receiptStatus === 'REJECTED' ? '客户已打回回执' : '待客户确认回执') : '待上传报关行回执' }}</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</tbody></table></div>
|
||||
</div>
|
||||
<div v-if="['DECLARING', 'COMPLETED'].includes(customs.status) && brokerSubmitted" class="compact-table-wrap declaration-batches-wrap">
|
||||
<div class="declaration-batches-heading"><div><h3>正式申报与海关结果</h3></div><el-button v-if="canManage && !openDeclarationBatch" size="small" type="primary" :loading="actionLoading" @click="createFormalDeclaration">创建正式申报批次</el-button></div>
|
||||
@@ -353,7 +354,7 @@ onMounted(load)
|
||||
<div v-if="customs.status === 'COMPLETED'" class="departure-state"><strong>国内离仓状态:</strong><el-tag :type="departureState === 'DEPARTED' ? 'success' : 'warning'">{{ departureState === 'DEPARTED' ? '已自动离仓' : departureState === 'UNKNOWN' ? '离仓状态尚未读取' : '报关已完成,待其他离仓条件' }}</el-tag></div>
|
||||
</template>
|
||||
<el-empty v-else-if="canList" description="当前装柜计划尚未完成,完成装柜后可处理报关" :image-size="56" />
|
||||
<AppDialog v-model="clearanceDialogVisible" class="admin-density-dialog" :title="customsDialogTitle('标记海关异常/结果', clearanceBatch)" width="460px" :close-on-click-modal="false" :lock-while-submitting="false" :confirm-loading="actionLoading" confirm-text="确认标记" @confirm="recordFormalResult">
|
||||
<AppDialog v-model="clearanceDialogVisible" class="admin-density-dialog admin-workbench is-dialog" :title="customsDialogTitle('标记海关异常/结果', clearanceBatch)" width="460px" :close-on-click-modal="false" :lock-while-submitting="false" :confirm-loading="actionLoading" confirm-text="确认标记" @confirm="recordFormalResult">
|
||||
<el-form label-position="top" class="density-form density-form--flush-end">
|
||||
<el-form-item label="选择理由" required>
|
||||
<el-select v-model="clearanceResultType" placeholder="请选择理由">
|
||||
@@ -369,5 +370,5 @@ onMounted(load)
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container-customs{padding:0;border:0}.customs-header{display:flex;align-items:center;justify-content:space-between;gap:var(--admin-space-5)}.customs-header h2,.compact-table-wrap h3{margin:0;font-size:var(--admin-font-section)}.customs-header p{margin:3px 0 0;color:var(--cc-muted);font-size:var(--admin-font-caption)}.customs-actions{display:flex;align-items:center;gap:var(--admin-space-3)}.action-error{margin-top:var(--admin-space-3);padding:var(--admin-space-3) var(--admin-space-4);border:1px solid var(--el-color-danger-light-5);border-radius:var(--admin-radius);background:var(--el-color-danger-light-9);color:var(--el-color-danger);font-size:var(--admin-font-caption)}.action-error :deep(.api-error-meta){margin-top:5px}.customs-summary{margin-top:var(--admin-space-4)!important}.customs-summary .submission-batch{grid-column:span 2}.coverage-missing{color:var(--el-color-danger)!important}.compact-table-wrap{margin-top:var(--admin-space-5);overflow-x:auto}.confirmation-history-note,.receipt-history-note{display:block;margin-top:var(--admin-space-2);color:var(--cc-muted)}.compact-table-wrap h3{margin-bottom:var(--admin-space-2)}.compact-table{width:100%}.document-table th:first-child{width:270px}.document-actions,.file-cell{display:flex;align-items:center;gap:var(--admin-space-2)}.file-cell span{display:block;max-width:210px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.readonly-label{color:var(--cc-muted)}.departure-state{display:flex;align-items:center;gap:var(--admin-space-3);margin-top:var(--admin-space-4);padding-top:var(--admin-space-4);border-top:1px solid var(--cc-border);font-size:var(--admin-font-body)}.declaration-batches-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--admin-space-4)}.declaration-batches-heading p{margin:3px 0 0;color:var(--cc-muted);font-size:var(--admin-font-caption)}.declaration-batch-list{display:grid;gap:var(--admin-space-3)}.declaration-batch-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--admin-space-2) var(--admin-space-4);padding:var(--admin-space-3) var(--admin-space-4);border:1px solid var(--cc-border);background:var(--cc-surface-muted)}.declaration-batch-main strong,.declaration-batch-main span{display:block}.declaration-batch-main span{margin-top:4px;color:var(--cc-muted);font-size:var(--admin-font-caption)}.declaration-batch-actions,.declaration-result-list{grid-column:1 / -1}.declaration-result-list{display:grid;gap:5px;padding-top:var(--admin-space-2);border-top:1px solid var(--cc-border)}.declaration-result-row{display:flex;align-items:center;gap:var(--admin-space-2);font-size:var(--admin-font-caption)}.declaration-result-row small{flex:1;color:var(--cc-muted)}
|
||||
.container-customs{padding:0;border:0}.customs-header{display:flex;align-items:center;justify-content:space-between;gap:var(--admin-space-5)}.customs-header h2,.compact-table-wrap h3{margin:0;font-size:var(--admin-font-section)}.customs-header p{margin:3px 0 0;color:var(--workbench-muted);font-size:var(--admin-font-caption)}.customs-actions{display:flex;align-items:center;gap:var(--admin-space-3)}.action-error{margin-top:var(--admin-space-3);padding:var(--admin-space-3) var(--admin-space-4);border:1px solid var(--el-color-danger-light-5);border-radius:var(--admin-radius);background:var(--el-color-danger-light-9);color:var(--el-color-danger);font-size:var(--admin-font-caption)}.action-error :deep(.api-error-meta){margin-top:5px}.customs-summary{margin-top:var(--admin-space-4)!important}.customs-summary .submission-batch{grid-column:span 2}.coverage-missing{color:var(--el-color-danger)!important}.compact-table-wrap{margin-top:var(--admin-space-5);overflow-x:auto}.confirmation-history-note,.receipt-history-note{display:block;margin-top:var(--admin-space-2);color:var(--workbench-muted)}.compact-table-wrap h3{margin-bottom:var(--admin-space-2)}.compact-table{width:100%}.document-table th:first-child{width:270px}.document-actions,.file-cell{display:flex;align-items:center;gap:var(--admin-space-2)}.file-cell span{display:block;max-width:210px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.readonly-label{color:var(--workbench-muted)}.departure-state{display:flex;align-items:center;gap:var(--admin-space-3);margin-top:var(--admin-space-4);padding-top:var(--admin-space-4);border-top:1px solid var(--workbench-border);font-size:var(--admin-font-body)}.declaration-batches-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--admin-space-4)}.declaration-batches-heading p{margin:3px 0 0;color:var(--workbench-muted);font-size:var(--admin-font-caption)}.declaration-batch-list{display:grid;gap:var(--admin-space-3)}.declaration-batch-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--admin-space-2) var(--admin-space-4);padding:var(--admin-space-3) var(--admin-space-4);border:1px solid var(--workbench-border);background:var(--workbench-surface-soft)}.declaration-batch-main strong,.declaration-batch-main span{display:block}.declaration-batch-main span{margin-top:4px;color:var(--workbench-muted);font-size:var(--admin-font-caption)}.declaration-batch-actions,.declaration-result-list{grid-column:1 / -1}.declaration-result-list{display:grid;gap:5px;padding-top:var(--admin-space-2);border-top:1px solid var(--workbench-border)}.declaration-result-row{display:flex;align-items:center;gap:var(--admin-space-2);font-size:var(--admin-font-caption)}.declaration-result-row small{flex:1;color:var(--workbench-muted)}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import InlineHelp from '@/shared/components/InlineHelp.vue'
|
||||
import '@/styles/adminDensity.css'
|
||||
import '@/styles/adminWorkbench.css'
|
||||
import { computed, onMounted, onBeforeUnmount, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getFinancePaymentVoucher, downloadFinancePaymentVoucher } from '@/modules/finance'
|
||||
@@ -165,7 +166,7 @@ onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="last-leg-fees admin-density">
|
||||
<div class="last-leg-fees admin-density admin-workbench">
|
||||
<header class="last-leg-fees__header"><div><h2>{{ title }}<InlineHelp title="费用统计说明"><p>按真实货柜展示港口、堆存、修箱、吊机和码头拖车费用,金额按币种分别列示。</p></InlineHelp></h2></div><el-button v-if="canEdit" type="primary" :disabled="!containerNo || customers.length === 0" @click="openCreate">新增费用</el-button></header>
|
||||
<el-alert v-if="canView && !canEdit && !canReview" type="info" :closable="false" title="当前账号仅有海外段费用查看权限。" />
|
||||
<el-alert v-if="!containerNo" type="warning" :closable="false" title="当前货柜尚未补录真实集装箱号,暂不能新增尾程费用。" />
|
||||
@@ -184,21 +185,21 @@ onMounted(load)
|
||||
<el-table-column label="作废确认" min-width="130"><template #default="{ row }">{{ voidLabels[row.voidStatus] || '—' }}</template></el-table-column>
|
||||
<el-table-column prop="reviewReason" label="审核说明" min-width="180" show-overflow-tooltip><template #default="{ row }">{{ row.reviewReason || '—' }}</template></el-table-column>
|
||||
</el-table>
|
||||
<AppDialog class="admin-density-dialog" v-model="dialogOpen" :title="containerDialogTitle(editing ? '调整尾程费用' : '新增尾程费用', props)" width="min(920px, calc(100vw - 28px))" fullscreenable confirm-text="保存" :confirm-loading="actionLoading" :confirm-disabled="voucherUploading" @confirm="save">
|
||||
<AppDialog class="admin-density-dialog admin-workbench is-dialog" v-model="dialogOpen" :title="containerDialogTitle(editing ? '调整尾程费用' : '新增尾程费用', props)" width="min(920px, calc(100vw - 28px))" fullscreenable confirm-text="保存" :confirm-loading="actionLoading" :confirm-disabled="voucherUploading" @confirm="save">
|
||||
<section class="density-dialog-section" data-tone="work">
|
||||
<el-form class="density-form" label-position="left">
|
||||
<table class="density-table density-table--editable fee-editor-table" aria-label="尾程费用填写"><tbody>
|
||||
<div class="workbench-evidence"><table class="density-table density-table--editable fee-editor-table" aria-label="尾程费用填写"><tbody>
|
||||
<tr><td><el-form-item label-position="left" label-width="110px" label="客户" required><span v-if="editing">{{ customerName(form.customerId) || editing.customerName || '—' }}</span><el-select v-else v-model="form.customerId" :disabled="voucherUploading" placeholder="请选择柜内客户"><el-option v-for="customer in customers" :key="customer.customerId" :label="customer.customerName || '未命名客户'" :value="customer.customerId" /></el-select></el-form-item></td><td><el-form-item label-position="left" label-width="110px" label="费用项目" required><el-select v-model="form.feeItemCode"><el-option v-for="item in feeItems" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item></td></tr>
|
||||
<tr><td><el-form-item label-position="left" label-width="110px" label="费用方向" required><el-select v-model="form.direction"><el-option label="应收" value="RECEIVABLE" /><el-option label="应付" value="PAYABLE" /></el-select></el-form-item></td><td><el-form-item label-position="left" label-width="110px" label="业务日期" required><el-date-picker v-model="form.businessDate" type="date" value-format="YYYY-MM-DD" /></el-form-item></td></tr>
|
||||
<tr><td :colspan="form.direction === 'PAYABLE' ? 1 : 2"><el-form-item label-position="left" label-width="110px" label="金额(CNY)" required><el-input-number v-model="form.amount" :min="0.01" :precision="2" :step="10" placeholder="请输入费用金额" /></el-form-item></td><td v-if="form.direction === 'PAYABLE'"><el-form-item label-position="left" label-width="110px" label="供应商" required><el-select v-model="form.supplierId" filterable placeholder="请选择有效供应商"><el-option v-for="supplier in suppliers" :key="supplier.id" :label="supplier.supplierName" :value="supplier.id" /></el-select></el-form-item></td></tr>
|
||||
<tr v-if="form.direction === 'PAYABLE'"><td :colspan="form.settlementMode === 'DIRECT_PAID' ? 1 : 2"><el-form-item label-position="left" label-width="110px" label="结算方式" required><el-select v-model="form.settlementMode"><el-option label="账期结算" value="ON_ACCOUNT" /><el-option label="直接已付" value="DIRECT_PAID" /></el-select></el-form-item></td><td v-if="form.settlementMode === 'DIRECT_PAID'"><el-form-item label-position="left" label-width="110px" label="付款时间" required><el-date-picker v-model="form.paidAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" /></el-form-item></td></tr>
|
||||
<tr v-if="form.direction === 'PAYABLE' && form.settlementMode === 'DIRECT_PAID'"><td><el-form-item label-position="left" label-width="110px" label="付款方式" required><el-select v-model="form.paymentMethod"><el-option label="线上支付" value="ONLINE" /><el-option label="银行转账" value="BANK_TRANSFER" /><el-option label="现金" value="CASH" /><el-option label="其他" value="OTHER" /></el-select></el-form-item></td><td><el-form-item label-position="left" label-width="110px" label="付款流水号"><el-input v-model="form.paymentReferenceNo" maxlength="128" /></el-form-item></td></tr>
|
||||
<tr v-if="form.direction === 'PAYABLE' && form.settlementMode === 'DIRECT_PAID'"><td :colspan="2"><el-form-item label-position="left" label-width="110px" label="付款凭证"><div class="voucher-list"><input ref="voucherInput" type="file" accept="image/*" hidden @change="uploadVoucher" /><el-button :loading="voucherUploading" :disabled="!form.customerId || actionLoading" @click="voucherInput?.click()">{{ form.paymentVoucherFileIds.length ? '重新上传凭证' : '上传付款凭证' }}</el-button><div v-for="(fileId, index) in form.paymentVoucherFileIds" :key="fileId" class="voucher-item"><el-button link type="primary" @click="previewVoucher(form.customerId, fileId)">{{ voucherNames[fileId] || `付款凭证 ${index + 1}` }}</el-button><el-button link type="danger" :disabled="voucherUploading || actionLoading" @click="form.paymentVoucherFileIds = form.paymentVoucherFileIds.filter((id) => id !== fileId)">移除</el-button></div></div></el-form-item></td></tr>
|
||||
</tbody></table>
|
||||
</tbody></table></div>
|
||||
</el-form>
|
||||
</section>
|
||||
</AppDialog>
|
||||
<AppDialog class="admin-density-dialog last-leg-voucher-dialog" v-model="previewOpen" :title="containerDialogTitle('付款凭证', props)" :fullscreenable="Boolean(previewUrl) && previewIsImage" width="min(900px, calc(100vw - 28px))" :show-confirm="false" cancel-text="关闭" append-to-body>
|
||||
<AppDialog class="admin-density-dialog last-leg-voucher-dialog admin-workbench is-dialog" v-model="previewOpen" :title="containerDialogTitle('付款凭证', props)" :fullscreenable="Boolean(previewUrl) && previewIsImage" width="min(900px, calc(100vw - 28px))" :show-confirm="false" cancel-text="关闭" append-to-body>
|
||||
<p v-if="previewLoading">正在读取付款凭证…</p>
|
||||
<div v-else-if="previewError"><el-alert type="error" :closable="false" :title="previewError.message" /><ApiErrorMeta :details="previewError" /></div>
|
||||
<div v-else-if="previewUrl" class="density-dialog-section voucher-preview" data-tone="source"><p class="density-dialog-note">{{ previewName }}</p><img v-if="previewIsImage" :src="previewUrl" :alt="previewName" /><p v-else>此文件暂不支持预览,请下载后查看。</p><a :href="previewUrl" :download="previewName">下载付款凭证</a></div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import '@/styles/adminWorkbench.css'
|
||||
import { computed, onBeforeUnmount, reactive, ref, watch } from 'vue'
|
||||
import { TriangleAlert } from '@lucide/vue'
|
||||
import { getApiErrorDetails } from '@/shared/api/http'
|
||||
@@ -120,15 +121,15 @@ onBeforeUnmount(() => { photoGeneration += 1; revokePhotoUrls() })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="overview-panel admin-density">
|
||||
<div class="overview-panel admin-density admin-workbench">
|
||||
<section v-if="visibleSections.has('exception')" class="overview-section exception-management" aria-label="异常管理">
|
||||
<header class="exception-management__header"><div><h3>异常管理</h3><p v-if="overview.exception.active" class="exception-current"><strong>{{ overview.exception.reason || '未填写异常原因' }}</strong><span>{{ overview.exception.markedByName || '操作人信息缺失' }} · {{ formatTime(overview.exception.markedAt) }}</span></p></div><div class="exception-management__actions"><StatusBadge :status="overview.exception.active ? '异常' : '正常'" /><el-button v-if="canManageException" :type="overview.exception.active ? 'primary' : 'danger'" plain @click="emit('manageException')"><TriangleAlert :size="16" />{{ overview.exception.active ? '取消异常' : '标记异常' }}</el-button></div></header>
|
||||
<div class="exception-history"><div class="exception-history__head"><span>时间</span><span>动作</span><span>操作人</span><span>原因</span></div><p v-if="overview.exceptionHistory.length === 0" class="exception-history__empty">暂无异常处理记录</p><ol v-else><li v-for="history in overview.exceptionHistory" :key="history.id"><time>{{ formatTime(history.occurredAt) }}</time><strong>{{ eventLabel(history.action) }}</strong><span>{{ history.operatorName || '操作人信息缺失' }}</span><span :title="history.reason">{{ history.reason }}</span></li></ol></div>
|
||||
<div class="exception-history"><p v-if="overview.exceptionHistory.length === 0" class="exception-history__empty">暂无异常处理记录</p><template v-else><div class="exception-history__head"><span>时间</span><span>动作</span><span>操作人</span><span>原因</span></div><ol><li v-for="history in overview.exceptionHistory" :key="history.id"><time>{{ formatTime(history.occurredAt) }}</time><strong>{{ eventLabel(history.action) }}</strong><span>{{ history.operatorName || '操作人信息缺失' }}</span><span :title="history.reason">{{ history.reason }}</span></li></ol></template></div>
|
||||
</section>
|
||||
|
||||
<section v-if="visibleSections.has('documents')" class="overview-section overview-section--documents" aria-label="报关清关资料">
|
||||
<div class="document-table-wrap">
|
||||
<table class="document-table density-table">
|
||||
<div class="workbench-evidence"><table class="document-table density-table">
|
||||
<thead><tr><th class="document-table__actions">操作</th><th>资料类型</th><th>资料内容</th><th>更新人</th><th>更新时间</th><th>状态</th></tr></thead>
|
||||
<tbody><tr v-for="item in documentTypes" :key="item.type">
|
||||
<td class="document-table__actions"><div class="document-actions density-actions"><el-button class="density-action" v-if="documentsByType.get(item.type) && canDownloadDocument(item.type)" size="small" :loading="documentBusy" @click="emit('downloadDocument', documentsByType.get(item.type)!)">下载</el-button><el-button class="density-action" v-if="canUploadDocument(item.type) && !documentsByType.get(item.type)?.completed" size="small" @click="emit('uploadDocument', item.type)">{{ documentsByType.get(item.type) ? '更新附件' : '上传附件' }}</el-button><span v-if="!hasDocumentAction(item.type)" class="no-action">—</span></div></td>
|
||||
@@ -145,7 +146,7 @@ onBeforeUnmount(() => { photoGeneration += 1; revokePhotoUrls() })
|
||||
<td>{{ formatTime(overview.container.pickupCodeUpdatedAt) }}</td>
|
||||
<td><el-tag size="small" :type="overview.container.pickupCode ? 'success' : 'info'">{{ overview.container.pickupCode ? '已填写' : '未填写' }}</el-tag></td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
</table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -165,13 +166,13 @@ onBeforeUnmount(() => { photoGeneration += 1; revokePhotoUrls() })
|
||||
.overview-section--documents{padding:0;border:0}
|
||||
.overview-section > header { display: flex; align-items: center; justify-content: space-between; gap: var(--admin-space-5); margin-bottom: var(--admin-space-5); }
|
||||
.overview-section h3 { margin: 0; font-size: var(--admin-font-section); }
|
||||
.overview-section header > span, .overview-section small { color: var(--cc-muted); font-size: var(--admin-font-caption); }
|
||||
.overview-section p { margin: 5px 0; color: var(--cc-muted); font-size: var(--admin-font-body); }
|
||||
.exception-management{padding-top:var(--admin-space-4);padding-bottom:var(--admin-space-4)}.exception-management__header{margin-bottom:7px!important}.exception-management__header>div:first-child{display:flex;min-width:0;align-items:center;gap:var(--admin-space-5)}.exception-current{display:flex;min-width:0;align-items:center;gap:9px;margin:0!important}.exception-current strong,.exception-current span{max-width:360px;white-space: normal;overflow-wrap: anywhere}.exception-current strong{color:var(--el-color-danger)}.exception-current span{font-size:var(--admin-font-caption)}.exception-management__actions{display:flex;align-items:center;gap:var(--admin-space-3)}.exception-history{overflow-x:auto;border-top:1px solid var(--cc-border);font-size:var(--admin-font-caption)}.exception-history__head,.exception-history li{display:grid;grid-template-columns:145px 120px 130px minmax(220px,1fr);gap:var(--admin-space-3);align-items:center;min-width:680px;padding:var(--admin-space-2) var(--admin-space-1)}.exception-history__head{color:var(--cc-muted);font-weight:650}.exception-history ol{margin:0;padding:0;list-style:none}.exception-history li{border-top:1px solid var(--cc-border)}.exception-history li time,.exception-history li span{color:var(--cc-muted);white-space: normal;overflow-wrap: anywhere}.exception-history__empty{margin:0!important;padding:7px var(--admin-space-1);border-top:1px solid var(--cc-border);font-size:var(--admin-font-caption)!important}
|
||||
.document-table-wrap{width:100%;overflow-x:auto;border:1px solid var(--cc-border)}.document-table{width:100%;min-width:940px;table-layout:fixed}.document-table tbody tr:last-child td{border-bottom:0}.document-table th:nth-child(1){width:260px}.document-table th:nth-child(2){width:180px}.document-table th:nth-child(3){width:210px}.document-table th:nth-child(4){width:120px}.document-table th:nth-child(5){width:150px}.document-table th:nth-child(6){width:90px}.document-table__actions{position:sticky;left:0;z-index:1;box-shadow:1px 0 0 var(--cc-border)}.document-table th.document-table__actions{z-index:2}.document-table td strong{font-size:var(--admin-font-body)}.document-table td small{display:block;overflow:hidden;max-width:170px;margin-top:2px;text-overflow:ellipsis;white-space:nowrap}.document-file-name{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.document-blocked-reason{color:var(--cc-muted)}.document-actions{white-space:nowrap}.document-actions :deep(.el-button){margin-left:0}.no-action{color:var(--cc-muted)}.pickup-code-row :deep(.el-input){max-width:260px}.pickup-code-row :deep(.el-input__inner){font-variant-numeric:tabular-nums}
|
||||
.overview-section header > span, .overview-section small { color: var(--workbench-muted); font-size: var(--admin-font-caption); }
|
||||
.overview-section p { margin: 5px 0; color: var(--workbench-muted); font-size: var(--admin-font-body); }
|
||||
.exception-management{padding-top:var(--admin-space-4);padding-bottom:var(--admin-space-4)}.exception-management__header{margin-bottom:7px!important}.exception-management__header>div:first-child{display:flex;min-width:0;align-items:center;gap:var(--admin-space-5)}.exception-current{display:flex;min-width:0;align-items:center;gap:9px;margin:0!important}.exception-current strong,.exception-current span{max-width:360px;white-space: normal;overflow-wrap: anywhere}.exception-current strong{color:var(--el-color-danger)}.exception-current span{font-size:var(--admin-font-caption)}.exception-management__actions{display:flex;align-items:center;gap:var(--admin-space-3)}.exception-history{overflow-x:auto;border-top:1px solid var(--workbench-border);font-size:var(--admin-font-caption)}.exception-history__head,.exception-history li{display:grid;grid-template-columns:145px 120px 130px minmax(220px,1fr);gap:var(--admin-space-3);align-items:center;min-width:680px;padding:var(--admin-space-2) var(--admin-space-1)}.exception-history__head{color:var(--workbench-muted);font-weight:650}.exception-history ol{margin:0;padding:0;list-style:none}.exception-history li{border-top:1px solid var(--workbench-border)}.exception-history li time,.exception-history li span{color:var(--workbench-muted);white-space: normal;overflow-wrap: anywhere}.exception-history__empty{margin:0!important;padding:7px var(--admin-space-1);border-top:1px solid var(--workbench-border);font-size:var(--admin-font-caption)!important}
|
||||
.document-table-wrap{width:100%;overflow-x:auto;border:1px solid var(--workbench-border)}.document-table{width:100%;min-width:940px;table-layout:fixed}.document-table tbody tr:last-child td{border-bottom:0}.document-table th:nth-child(1){width:260px}.document-table th:nth-child(2){width:180px}.document-table th:nth-child(3){width:210px}.document-table th:nth-child(4){width:120px}.document-table th:nth-child(5){width:150px}.document-table th:nth-child(6){width:90px}.document-table__actions{position:sticky;left:0;z-index:1;box-shadow:1px 0 0 var(--workbench-border)}.document-table th.document-table__actions{z-index:2}.document-table td strong{font-size:var(--admin-font-body)}.document-table td small{display:block;overflow:hidden;max-width:170px;margin-top:2px;text-overflow:ellipsis;white-space:nowrap}.document-file-name{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.document-blocked-reason{color:var(--workbench-muted)}.document-actions{white-space:nowrap}.document-actions :deep(.el-button){margin-left:0}.no-action{color:var(--workbench-muted)}.pickup-code-row :deep(.el-input){max-width:260px}.pickup-code-row :deep(.el-input__inner){font-variant-numeric:tabular-nums}
|
||||
.overview-panel .pda-summary { grid-template-columns: minmax(280px, 2fr) repeat(4, minmax(0, 1fr)); margin-bottom: var(--admin-space-4); }
|
||||
.pda-progress dd { width: 100%; }
|
||||
.photo-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,220px));gap:var(--admin-space-3);margin:var(--admin-space-4) 0}.photo-thumb{display:grid;min-width:0;overflow:hidden;padding:0;border:1px solid var(--cc-border);background:var(--admin-surface);color:inherit;text-align:left;cursor:pointer}.photo-thumb:disabled{cursor:default}.photo-thumb img,.photo-placeholder{width:100%;height:112px;object-fit:contain;background:var(--cc-bg-subtle,#f7f8fa)}.photo-placeholder{display:grid;place-items:center;padding:var(--admin-space-3);color:var(--cc-muted);font-size:var(--admin-font-caption)}.photo-placeholder--error{color:var(--el-color-danger)}.photo-caption{display:grid;gap:var(--admin-space-2);padding:var(--admin-space-2) var(--admin-space-3)}.photo-caption small{white-space:nowrap}.compact-empty{margin:var(--admin-space-2) 0;color:var(--cc-muted);font-size:var(--admin-font-caption)}.compact-timeline{display:grid;margin:0;padding:0;list-style:none}.compact-timeline li{display:grid;grid-template-columns:130px 130px 110px minmax(0,1fr);gap:var(--admin-space-3);padding:var(--admin-space-2) 0;border-top:1px solid var(--cc-border);font-size:var(--admin-font-caption)}.compact-timeline li:first-child{border-top:0}.compact-timeline time,.compact-timeline span,.compact-timeline small{overflow:hidden;color:var(--cc-muted);text-overflow:ellipsis;white-space:nowrap}
|
||||
.photo-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,220px));gap:var(--admin-space-3);margin:var(--admin-space-4) 0}.photo-thumb{display:grid;min-width:0;overflow:hidden;padding:0;border:1px solid var(--workbench-border);background:var(--admin-surface);color:inherit;text-align:left;cursor:pointer}.photo-thumb:disabled{cursor:default}.photo-thumb img,.photo-placeholder{width:100%;height:112px;object-fit:contain;background:var(--cc-bg-subtle,#f7f8fa)}.photo-placeholder{display:grid;place-items:center;padding:var(--admin-space-3);color:var(--workbench-muted);font-size:var(--admin-font-caption)}.photo-placeholder--error{color:var(--el-color-danger)}.photo-caption{display:grid;gap:var(--admin-space-2);padding:var(--admin-space-2) var(--admin-space-3)}.photo-caption small{white-space:nowrap}.compact-empty{margin:var(--admin-space-2) 0;color:var(--workbench-muted);font-size:var(--admin-font-caption)}.compact-timeline{display:grid;margin:0;padding:0;list-style:none}.compact-timeline li{display:grid;grid-template-columns:130px 130px 110px minmax(0,1fr);gap:var(--admin-space-3);padding:var(--admin-space-2) 0;border-top:1px solid var(--workbench-border);font-size:var(--admin-font-caption)}.compact-timeline li:first-child{border-top:0}.compact-timeline time,.compact-timeline span,.compact-timeline small{overflow:hidden;color:var(--workbench-muted);text-overflow:ellipsis;white-space:nowrap}
|
||||
@media (max-width: 1200px){.photo-gallery{grid-template-columns:repeat(4,minmax(0,1fr))}.overview-panel .pda-summary{grid-template-columns:1fr 1fr}.compact-timeline li{grid-template-columns:120px 120px minmax(0,1fr)}.compact-timeline small{grid-column:2/-1}}
|
||||
@media (max-width: 720px) { .exception-management__header{align-items:flex-start;flex-direction:column}.exception-management__header>div:first-child{align-items:flex-start;flex-direction:column;gap:3px}.exception-current{align-items:flex-start;flex-direction:column;gap:2px}.photo-gallery{grid-template-columns:repeat(2,minmax(0,1fr))}.compact-timeline li{grid-template-columns:1fr 1fr}.compact-timeline span,.compact-timeline small{grid-column:auto;white-space:normal} }
|
||||
</style>
|
||||
|
||||
@@ -23,6 +23,7 @@ describe('ContainerSimulationCreate opted-in form', () => {
|
||||
await wrapper.findAll('button').find(button => button.text().includes('新增模拟柜'))!.trigger('click')
|
||||
await flushPromises()
|
||||
const dialog = wrapper.findComponent(AppDialog)
|
||||
expect(dialog.props('width')).toBe(dense ? 'min(1000px, calc(100vw - 28px))' : 'min(560px, calc(100vw - 28px))')
|
||||
dialog.vm.$emit('confirm')
|
||||
await flushPromises()
|
||||
expect(createContainerSimulation).not.toHaveBeenCalled()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import '@/styles/adminWorkbench.css'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { Plus } from '@lucide/vue'
|
||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||
@@ -95,9 +96,9 @@ async function saveSimulation() {
|
||||
|
||||
<template>
|
||||
<el-button type="primary" @click="openSimulation"><Plus :size="16" />新增模拟柜</el-button>
|
||||
<AppDialog :class="{ 'admin-density-dialog': dense }" v-model="simulationOpen" title="新增模拟柜" width="min(560px, calc(100vw - 28px))" confirm-text="创建模拟柜" cancel-text="取消" :confirm-loading="simulationSaving" @confirm="saveSimulation">
|
||||
<AppDialog class="admin-workbench is-dialog" :class="{ 'admin-density-dialog': dense }" v-model="simulationOpen" title="新增模拟柜" :width="dense ? 'min(1000px, calc(100vw - 28px))' : 'min(560px, calc(100vw - 28px))'" confirm-text="创建模拟柜" cancel-text="取消" :confirm-loading="simulationSaving" @confirm="saveSimulation">
|
||||
|
||||
<section :class="{ 'density-dialog-section': dense }" data-tone="work"> <el-form ref="simulationFormRef" :model="simulationForm" :rules="simulationRules" :label-position="dense ? 'left' : 'top'" :label-width="dense ? '120px' : undefined" class="simulation-form" :class="{ 'density-form': dense }"><template v-if="dense"><table :class="{ 'density-table': dense, 'density-table--editable': dense }" aria-label="模拟柜资料"><tbody><tr><td><el-form-item label="装柜仓库" prop="warehouseId"><el-select :model-value="simulationForm.warehouseId" filterable placeholder="请选择国内装柜仓库" :loading="warehouseLoading" @update:model-value="selectSimulationWarehouse"><el-option v-for="warehouse in warehouses" :key="String(warehouse.id)" :label="warehouse.warehouseName" :value="String(warehouse.id)" /></el-select></el-form-item></td><td><el-form-item label="物流渠道" prop="channelGroupCode"><el-select v-model="simulationForm.channelGroupCode" filterable :disabled="!simulationForm.warehouseId || simulationChannelsLoading" :loading="simulationChannelsLoading" :placeholder="simulationForm.warehouseId ? '请选择物流渠道' : '请先选择装柜仓库'" no-data-text="当前仓库暂无有效渠道"><el-option v-for="group in simulationChannelGroups" :key="group.code" :label="group.name" :value="group.code" /></el-select></el-form-item></td></tr><tr><td><el-form-item label="柜型" prop="containerType"><el-select :model-value="simulationForm.containerType" @update:model-value="selectSimulationContainerType(String($event || ''))"><el-option v-for="item in CONTAINER_SPECIFICATIONS" :key="item.type" :label="item.type" :value="item.type" /></el-select></el-form-item></td><td><el-form-item label="统一规格"><span>{{ `${containerSpecification(simulationForm.containerType)?.recommendedMinCbm || '—'}–${containerSpecification(simulationForm.containerType)?.capacityCbm || '—'} m³ / 货重 ≤ ${containerSpecification(simulationForm.containerType)?.maxWeightKg || '—'} kg` }}</span><small :class="{ 'density-dialog-note': dense }">{{ containerSpecification(simulationForm.containerType)?.description }}</small></el-form-item></td></tr></tbody></table></template><template v-else><el-form-item label="装柜仓库" prop="warehouseId"><el-select :model-value="simulationForm.warehouseId" filterable placeholder="请选择国内装柜仓库" :loading="warehouseLoading" @update:model-value="selectSimulationWarehouse"><el-option v-for="warehouse in warehouses" :key="String(warehouse.id)" :label="warehouse.warehouseName" :value="String(warehouse.id)" /></el-select></el-form-item><el-form-item label="物流渠道" prop="channelGroupCode"><el-select v-model="simulationForm.channelGroupCode" filterable :disabled="!simulationForm.warehouseId || simulationChannelsLoading" :loading="simulationChannelsLoading" :placeholder="simulationForm.warehouseId ? '请选择物流渠道' : '请先选择装柜仓库'" no-data-text="当前仓库暂无有效渠道"><el-option v-for="group in simulationChannelGroups" :key="group.code" :label="group.name" :value="group.code" /></el-select></el-form-item><el-form-item label="柜型" prop="containerType"><el-select :model-value="simulationForm.containerType" @update:model-value="selectSimulationContainerType(String($event || ''))"><el-option v-for="item in CONTAINER_SPECIFICATIONS" :key="item.type" :label="item.type" :value="item.type" /></el-select></el-form-item><el-form-item label="统一规格"><el-input :model-value="`${containerSpecification(simulationForm.containerType)?.recommendedMinCbm || '—'}–${containerSpecification(simulationForm.containerType)?.capacityCbm || '—'} m³ / 货重 ≤ ${containerSpecification(simulationForm.containerType)?.maxWeightKg || '—'} kg`" disabled /><small>{{ containerSpecification(simulationForm.containerType)?.description }}</small></el-form-item></template></el-form></section>
|
||||
<section class="admin-workbench" :class="{ 'density-dialog-section': dense }" data-tone="work"> <el-form ref="simulationFormRef" :model="simulationForm" :rules="simulationRules" :label-position="dense ? 'left' : 'top'" :label-width="dense ? '120px' : undefined" class="simulation-form" :class="{ 'density-form': dense }"><template v-if="dense"><div class="workbench-evidence"><table :class="{ 'density-table': dense, 'density-table--editable': dense }" aria-label="模拟柜资料"><tbody><tr><td><el-form-item label="装柜仓库" prop="warehouseId"><el-select :model-value="simulationForm.warehouseId" filterable placeholder="请选择国内装柜仓库" :loading="warehouseLoading" @update:model-value="selectSimulationWarehouse"><el-option v-for="warehouse in warehouses" :key="String(warehouse.id)" :label="warehouse.warehouseName" :value="String(warehouse.id)" /></el-select></el-form-item></td><td><el-form-item label="物流渠道" prop="channelGroupCode"><el-select v-model="simulationForm.channelGroupCode" filterable :disabled="!simulationForm.warehouseId || simulationChannelsLoading" :loading="simulationChannelsLoading" :placeholder="simulationForm.warehouseId ? '请选择物流渠道' : '请先选择装柜仓库'" no-data-text="当前仓库暂无有效渠道"><el-option v-for="group in simulationChannelGroups" :key="group.code" :label="group.name" :value="group.code" /></el-select></el-form-item></td></tr><tr><td><el-form-item label="柜型" prop="containerType"><el-select :model-value="simulationForm.containerType" @update:model-value="selectSimulationContainerType(String($event || ''))"><el-option v-for="item in CONTAINER_SPECIFICATIONS" :key="item.type" :label="item.type" :value="item.type" /></el-select></el-form-item></td><td><el-form-item label="统一规格"><span>{{ `${containerSpecification(simulationForm.containerType)?.recommendedMinCbm || '—'}–${containerSpecification(simulationForm.containerType)?.capacityCbm || '—'} m³ / 货重 ≤ ${containerSpecification(simulationForm.containerType)?.maxWeightKg || '—'} kg` }}</span><small :class="{ 'density-dialog-note': dense }">{{ containerSpecification(simulationForm.containerType)?.description }}</small></el-form-item></td></tr></tbody></table></div></template><template v-else><el-form-item label="装柜仓库" prop="warehouseId"><el-select :model-value="simulationForm.warehouseId" filterable placeholder="请选择国内装柜仓库" :loading="warehouseLoading" @update:model-value="selectSimulationWarehouse"><el-option v-for="warehouse in warehouses" :key="String(warehouse.id)" :label="warehouse.warehouseName" :value="String(warehouse.id)" /></el-select></el-form-item><el-form-item label="物流渠道" prop="channelGroupCode"><el-select v-model="simulationForm.channelGroupCode" filterable :disabled="!simulationForm.warehouseId || simulationChannelsLoading" :loading="simulationChannelsLoading" :placeholder="simulationForm.warehouseId ? '请选择物流渠道' : '请先选择装柜仓库'" no-data-text="当前仓库暂无有效渠道"><el-option v-for="group in simulationChannelGroups" :key="group.code" :label="group.name" :value="group.code" /></el-select></el-form-item><el-form-item label="柜型" prop="containerType"><el-select :model-value="simulationForm.containerType" @update:model-value="selectSimulationContainerType(String($event || ''))"><el-option v-for="item in CONTAINER_SPECIFICATIONS" :key="item.type" :label="item.type" :value="item.type" /></el-select></el-form-item><el-form-item label="统一规格"><el-input :model-value="`${containerSpecification(simulationForm.containerType)?.recommendedMinCbm || '—'}–${containerSpecification(simulationForm.containerType)?.capacityCbm || '—'} m³ / 货重 ≤ ${containerSpecification(simulationForm.containerType)?.maxWeightKg || '—'} kg`" disabled /><small>{{ containerSpecification(simulationForm.containerType)?.description }}</small></el-form-item></template></el-form></section>
|
||||
<LoadErrorState v-if="simulationError" compact title="模拟柜创建失败" :message="simulationError.message" :show-retry="false"><template #details><ApiErrorMeta :details="simulationError" /></template></LoadErrorState>
|
||||
</AppDialog>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import '@/styles/adminWorkbench.css'
|
||||
import { ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { listOceanBookingLinkCandidates } from '@/modules/ocean-bookings'
|
||||
@@ -99,14 +100,14 @@ defineExpose({ candidates, candidateKey, containerNo, save })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppDialog class="admin-density-dialog" :model-value="modelValue" :title="containerDialogTitle('关联已放舱订舱', container)" fullscreenable width="min(680px, calc(100vw - 28px))" confirm-text="确认关联" cancel-text="取消" :confirm-loading="saving" :confirm-disabled="!candidateKey" @update:model-value="emit('update:modelValue', $event)" @confirm="save">
|
||||
<AppDialog class="admin-density-dialog admin-workbench is-dialog" :model-value="modelValue" :title="containerDialogTitle('关联已放舱订舱', container)" fullscreenable width="min(680px, calc(100vw - 28px))" confirm-text="确认关联" cancel-text="取消" :confirm-loading="saving" :confirm-disabled="!candidateKey" @update:model-value="emit('update:modelValue', $event)" @confirm="save">
|
||||
<section class="density-dialog-section" data-tone="work">
|
||||
<el-form class="density-form" label-position="left" label-width="160px">
|
||||
<table class="density-table density-table--editable" aria-label="关联订舱资料"><tbody>
|
||||
<div class="workbench-evidence"><table class="density-table density-table--editable" aria-label="关联订舱资料"><tbody>
|
||||
<tr><td><el-form-item label="柜次号"><span>{{ container?.cabinetNo || '—' }}</span></el-form-item></td></tr>
|
||||
<tr><td><el-form-item label="已放舱订舱及柜型需求" required><el-select v-model="candidateKey" filterable :loading="loading" placeholder="请选择仍有剩余数量的柜型需求" no-data-text="暂无符合当前装柜仓库、物流渠道和柜型的已放舱需求"><el-option v-for="candidate in candidates" :key="candidate.key" :label="candidate.label" :value="candidate.key" /></el-select></el-form-item></td></tr>
|
||||
<tr><td><el-form-item label="真实集装箱号(可选)"><el-input v-model="containerNo" maxlength="64" placeholder="如未取得可留空,后续显示待补录" @blur="containerNo = normalizeContainerNo(containerNo)" /></el-form-item></td></tr>
|
||||
</tbody></table>
|
||||
</tbody></table></div>
|
||||
</el-form>
|
||||
</section>
|
||||
<LoadErrorState v-if="error" compact title="关联失败" :message="error.message" :show-retry="false"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||||
|
||||
@@ -46,8 +46,9 @@ describe('SmartLoadingDialog', () => {
|
||||
expect(source).toContain('.smart-loading-dialog.app-dialog.el-dialog:not(.is-fullscreen)')
|
||||
expect(source).toContain('height: 94vh; max-height: 94vh;')
|
||||
expect(source).not.toContain('.smart-loading-dialog.app-dialog.el-dialog) { width: min(1600px, 98vw)')
|
||||
expect(source).toContain('.smart-loading-dialog.app-dialog.admin-density-dialog .el-dialog__body')
|
||||
expect(source).toContain('.smart-loading-dialog.app-dialog.admin-density-dialog > .el-dialog__body')
|
||||
expect(source).toContain('flex: 1; padding: 0; overflow: hidden;')
|
||||
expect(source).toContain('min-height: 0; flex: 1; overflow: hidden;')
|
||||
expect(source).toContain('min-height: 0; flex: 1; padding: var(--admin-space-5); box-sizing: border-box; overflow: hidden;')
|
||||
expect(source).toContain('width="min(1840px, calc(100vw - 48px))"')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import '@/styles/adminWorkbench.css'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import GlobalSmartLoadingView from '../pages/GlobalSmartLoadingView.vue'
|
||||
|
||||
@@ -9,9 +10,9 @@ const open = defineModel<boolean>({ default: false })
|
||||
<template>
|
||||
<AppDialog
|
||||
v-model="open"
|
||||
class="smart-loading-dialog admin-density-dialog"
|
||||
class="smart-loading-dialog admin-density-dialog admin-workbench is-dialog"
|
||||
title="智能装柜"
|
||||
width="min(1600px, 98vw)"
|
||||
width="min(1840px, calc(100vw - 48px))"
|
||||
fullscreenable
|
||||
default-fullscreen
|
||||
cancel-text="关闭"
|
||||
@@ -23,9 +24,9 @@ const open = defineModel<boolean>({ default: false })
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:global(.smart-loading-dialog.app-dialog.el-dialog:not(.is-fullscreen)) { width: min(1600px, 98vw); height: 94vh; max-height: 94vh; margin-block: 3vh !important; }
|
||||
:global(.smart-loading-dialog.app-dialog.admin-density-dialog .el-dialog__body) { display: flex; min-height: 0; flex: 1; padding: 0; overflow: hidden; }
|
||||
:global(.smart-loading-dialog .app-dialog__body) { display: flex; min-width: 0; min-height: 0; flex: 1; overflow: hidden; }
|
||||
:global(.smart-loading-dialog.app-dialog.el-dialog:not(.is-fullscreen)) { width: min(1840px, calc(100vw - 48px)); height: 94vh; max-height: 94vh; margin-block: 3vh !important; }
|
||||
:global(.smart-loading-dialog.app-dialog.admin-density-dialog > .el-dialog__body) { display: flex; min-height: 0; flex: 1; padding: 0; overflow: hidden; }
|
||||
:global(.smart-loading-dialog > .el-dialog__body > .app-dialog__body) { display: flex; min-width: 0; min-height: 0; flex: 1; padding: var(--admin-space-5); box-sizing: border-box; overflow: hidden; }
|
||||
@media (max-width: 720px) {
|
||||
:global(.smart-loading-dialog.app-dialog.el-dialog:not(.is-fullscreen)) { width: calc(100vw - 12px); height: calc(100svh - 12px); max-height: calc(100svh - 12px); margin-block: 6px !important; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user