@@ -4,9 +4,13 @@ import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { ChevronDown , ChevronUp , ClipboardCheck , Eye , Printer , RefreshCw , SlidersHorizontal } from '@lucide/vue'
import { getApiErrorDetails , type ApiErrorDetails } from '@/shared/api/http'
import AdminPage from '@/shared/components/AdminPage.vue'
import AppDrawer from '@/shared/components/AppDrawer.vue'
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
import DataTable , { type DataTableColumn } from '@/shared/components/DataTable.vue'
import DetailPageLayout from '@/shared/components/DetailPageLayout.vue'
import FormSection from '@/shared/components/FormSection.vue'
import ListPageLayout from '@/shared/components/ListPageLayout.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import QueryToolbar , { type QueryField , type QueryModel } from '@/shared/components/QueryToolbar.vue'
import { listPlatformTenants , type PlatformTenantResource } from '@/modules/iam'
@@ -400,25 +404,32 @@ onBeforeUnmount(() => { disposed = true; loadRequestId += 1; detailRequestId +=
< / script >
< template >
< div class = "business-page inbound-orders-page" >
< QueryToolbar v-model = "filters" class="surface-panel inbound-query-toolbar" ariaLabel="入库单筛选" :fields="queryFields" :available-fields="allQueryFields" preference-key="inbound-orders-query" :search-on-reset="false" @search="applyFilters" @reset="resetFilters " >
< template # actions >
< el-button :aria-expanded = "showAdvancedFilters" @click ="toggleAdvanced Filters">
< SlidersHorizontal :size = "16" / >
{ { showAdvancedFilters ? '收起筛选' : '更多筛选' } }
< ChevronUp v-if = "showAdvancedFilters" :size= "15 " / >
< ChevronDown v-else :size = "15" / >
< / el-button >
< AdminPage as = "div" class = "business-page inbound-orders-page" >
< ListPageLayout ariaLabel = "入库单管理 " >
< template # toolbar >
< QueryToolbar v-model = "filters" class="surface-panel inbound-query-toolbar" ariaLabel="入库单筛选" :fields="queryFields" :available-fields="allQueryFields" preference-key="inbound-orders-query" :search-on-reset="false" @search="applyFilters" @reset="reset Filters">
< template # actions >
< el-button :aria-expanded = "showAdvancedFilters" @click ="toggleAdvancedFilters" >
< SlidersHorizontal :size = "16 " / >
{ { showAdvancedFilters ? '收起筛选' : '更多筛选' } }
< ChevronUp v-if = "showAdvancedFilters" :size="15" / >
< ChevronDown v-else :size = "15" / >
< / el-button >
< / template >
< / QueryToolbar >
< / template >
< / QueryToolbar >
< el-alert v-if = "customerLoadError" type="warning" :closable="false" show-icon role="alert" >
< template # title > < div class = "api-error-alert-title" > < span > { { customerLoadError . message } } < / span > < ApiErrorMeta :details = "customerLoadError" / > < / div > < / template >
< el-button link type = "warning" :loading = "customersLoading" @click ="loadCustom ers "> 重新加载客户列表 < / el -button >
< / el-alert >
< template v-if = "customerLoadError || loadError" # state >
< div class = "inbound-state-stack" >
< el-alert v-if = "customerLoadError" type="warning" :closable="false" show-icon role="al ert ">
< template # title > < div class = "api-error-alert-title" > < span > { { customerLoadError . message } } < / span > < ApiErrorMeta :details = "customerLoadError" / > < / div > < / template >
< el-button link type = "warning" :loading = "customersLoading" @click ="loadCustomers" > < RefreshCw :size = "15" / > 重新加载客户列表 < / el-button >
< / el-alert >
< LoadErrorState v-if = "loadError" :message="loadError.message" title="入库单暂时无法加载" @retry="loadInbounds"><template #details><ApiErrorMeta :details="loadError" / > < / template > < / LoadErrorState >
< / div >
< / template >
< LoadErrorState v-if = "loadError" class="inbound-load-error" :message="loadError.message" title="入库单暂时无法加载" @retry="loadInbounds"><template #details><ApiErrorMeta :details="loadError" / > < / template > < / LoadErrorState >
< section v-else class = "surface-panel table-panel" :aria-busy = "loading" >
< section v-if = "! loadError" class="surface-panel table-panel" :aria-busy="loading" >
< header class = "table-toolbar" >
< div class = "table-tabs-row" >
< nav class = "inbound-tabs" role = "tablist" aria -label = " 入库单处理状态 " >
@@ -426,7 +437,6 @@ onBeforeUnmount(() => { disposed = true; loadRequestId += 1; detailRequestId +=
< / nav >
< / div >
< div class = "inbound-stats-row" aria -label = " 入库单统计 " >
< span class = "selected-info" > 当前显示 { { currentPageCount } } 条 · 共 { { result . total } } 条 < / span >
< span class = "total-info" >
< b > 总箱数 { { formatAggregate ( aggregateStats . packages , 0 ) } } < / b >
< i aria -hidden = " true " / >
@@ -439,8 +449,7 @@ onBeforeUnmount(() => { disposed = true; loadRequestId += 1; detailRequestId +=
< / div >
< / header >
< DataTable v -model :page = "page" v -model :page-size = "pageSize" :data = "result.records" :columns = "columns" preference -key = " inbound -orders -table " :loading = "loading" :total = "result.total" : page -sizes = " [ 20 , 50 , 100 ] " row -key = " id " :empty-text = "listEmptyText" aria -label = " 入库单列表 " >
< template # toolbar -start > < div > < h2 > 入库单列表 < / h2 > < p > 所属企业 { { selectedCustomerName } } < / p > < / div > < / template >
< template # toolbar -actions > < el-button :loading = "loading" @click ="loadInbounds" > < RefreshCw :size = "16" / > 刷新 < / el-button > < / template >
< template # pagination -left > 当前显示 { { currentPageCount } } 条 · 共 { { result . total } } 条 < / template >
< template # actions = "{ row }" > < div class = "row-actions" > < el-button link type = "primary" @click ="openWorkspace(row as InboundOrderSummary)" > < ClipboardCheck :size = "15" / > 处理 < / el-button > < el-button link : loading = "printingInboundId === (row as InboundOrderSummary).id" :disabled = "Boolean(printingInboundId)" @click ="printCartonLabels(row as InboundOrderSummary)" > < Printer :size = "15" / > 打印箱唛 < / el-button > < el-button link @click ="openDetail(row as InboundOrderSummary)" > < Eye :size = "15" / > 查看 < / el-button > < / div > < / template >
< template # inbound = "{ row }" > < div class = "primary-cell" > < strong > { { text ( ( row as InboundOrderSummary ) . inboundCode ) } } < / strong > < span > 订单 { { text ( ( row as InboundOrderSummary ) . orderNo ) } } < / span > < / div > < / template >
< template # orderStatus = "{ row }" > < div class = "status-stack" > < el-tag : type = "statusType((row as InboundOrderSummary).processStatus)" effect = "light" > { { statusLabel ( ( row as InboundOrderSummary ) . processStatus ) } } < / el-tag > < span > 订单 : { { text ( ( row as InboundOrderSummary ) . orderStatusSnapshot ) } } < / span > < / div > < / template >
@@ -481,13 +490,19 @@ onBeforeUnmount(() => { disposed = true; loadRequestId += 1; detailRequestId +=
< template # createdAt = "{ row }" > { { formatDate ( ( row as InboundOrderSummary ) . createdAt ) } } < / template >
< template # empty > < el-empty :description = "listEmptyText" / > < / template >
< / DataTable >
< / section >
< / section >
< / ListPageLayout >
< AppDrawer v-model = "detailOpen" :title="detail ? `入库单详情 · ${detail.summary.inboundCode || detail.summary.id}` : '入库单详情'" size="min(720px, 94vw)" :loading="detailLoading" :show-footer="false" destroy-on-close @closed="closeDetail" >
< section v-if = "detailError" class="detail-error" role="alert"><strong>入库单详情暂时无法加载</strong><p>{{ detailError.message }}</p><ApiErrorMeta :details="detailError" /><el-button type="primary" :disabled="!detailTarget" @click="detailTarget && openDetail(detailTarget)" > 重新加载 < / el -button > < / section >
< div v-else-if = "detail" class="detail-content"><InboundSummaryPanel :summary="detail.summary" :public-remark="detail.publicRemark" /><InboundHistoryPanel :pallet-locations="detail.palletLocations" :fi les ="detail.files" :internal-notes="detail.internalNotes" :status-history="detail.statusHistory" :public-remark="null" / > < / div >
< DetailPageLayout aria -label = " 入库单详情抽屉 " >
< section v-if = "detailError " class="detail-error" role="alert"><strong>入库单详情暂时无法加载</strong><p>{{ detailError.message }}</p><ApiErrorMeta :details="detailError" /><el-button type="primary" :disab led ="! detailTarget" @click="detailTarget && openDetail(detailTarget)"><RefreshCw :size="16" / > 重新加载 < / el-button > < / section >
< div v-else-if = "detail" class="detail-content" >
< FormSection title = "入库概览" > < InboundSummaryPanel :summary = "detail.summary" :public-remark = "detail.publicRemark" / > < / FormSection >
< FormSection title = "资源与状态记录" :bordered = "false" > < InboundHistoryPanel :pallet-locations = "detail.palletLocations" :files = "detail.files" :internal-notes = "detail.internalNotes" :status-history = "detail.statusHistory" :public-remark = "null" / > < / FormSection >
< / div >
< / DetailPageLayout >
< / AppDrawer >
< / div >
< / AdminPage >
< / template >
< style scoped >
@@ -499,7 +514,7 @@ onBeforeUnmount(() => { disposed = true; loadRequestId += 1; detailRequestId +=
. inbound - tab : hover { color : var ( -- cc - primary ) ; background : # f8fbff ; }
. inbound - tab : focus - visible { outline : 3 px solid rgba ( 102 , 126 , 234 , .2 ) ; outline - offset : 1 px ; }
. inbound - tab . is - active { border - bottom - color : var ( -- cc - primary ) ; background : # fff ; color : var ( -- cc - primary ) ; font - weight : 650 ; }
. inbound - load - error { margin - top : 12 px ; }
. inbound - state - stack { display : grid ; min - width : 0 ; gap : 12 px ; }
. row - actions { display : flex ; align - items : center ; gap : 2 px ; white - space : nowrap ; }
. row - actions : deep ( . el - button ) { margin - left : 0 ; }
. table - toolbar { display : grid ; min - width : 0 ; border - bottom : 1 px solid var ( -- cc - border ) ; }
@@ -521,4 +536,5 @@ onBeforeUnmount(() => { disposed = true; loadRequestId += 1; detailRequestId +=
. detail - error : deep ( . el - button ) { margin - top : 14 px ; }
@ media ( max - width : 900 px ) { . inbound - tabs { width : 100 % ; } }
@ media ( max - width : 720 px ) { . inbound - tab { padding - inline : 14 px ; } . table - tabs - row { padding : 0 10 px ; } . inbound - stats - row { min - height : 0 ; align - items : stretch ; flex - direction : column ; gap : 10 px ; padding : 10 px ; } . inbound - stats - row . total - info { justify - content : flex - start ; } }
@ media ( max - width : 360 px ) { . inbound - tab { padding - inline : 12 px ; } . row - actions { align - items : flex - start ; flex - direction : column ; } }
< / style >