优化
This commit is contained in:
@@ -190,9 +190,10 @@ describe('LocationsView', () => {
|
||||
|
||||
const tableToolbar = wrapper.find('.table-panel .data-table__toolbar')
|
||||
expect(tableToolbar.exists()).toBe(true)
|
||||
expect(tableToolbar.text()).toContain('库位列表')
|
||||
expect(tableToolbar.text()).toContain('共 2 个库位')
|
||||
expect(tableToolbar.text()).toContain('新增库位')
|
||||
expect(tableToolbar.text()).not.toContain('库位列表')
|
||||
expect(tableToolbar.text()).not.toContain('共 2 个库位')
|
||||
expect(wrapper.find('.data-table__pagination-left').text()).toContain('共 2 个库位')
|
||||
expect(wrapper.findComponent(QueryToolbar).text()).not.toContain('新增库位')
|
||||
expect(listAllPlatformWarehouses).toHaveBeenCalledWith({ warehouseType: 'DOMESTIC' })
|
||||
expect(listPlatformLocations).toHaveBeenLastCalledWith({
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { Eye, MapPin, MoreHorizontal, Pencil, Plus, Power, Trash2 } from '@lucide/vue'
|
||||
import { Eye, MapPin, MoreHorizontal, Pencil, Plus, Power, Save, Trash2 } from '@lucide/vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useUnsavedWorkRegistration } from '@/core/unsaved-work/useUnsavedWorkRegistration'
|
||||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import AdminPage from '@/shared/components/AdminPage.vue'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
import AppDrawer from '@/shared/components/AppDrawer.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.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 {
|
||||
changePlatformLocationStatus,
|
||||
@@ -499,32 +504,38 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="business-page location-page">
|
||||
<QueryToolbar
|
||||
v-model="filters"
|
||||
ariaLabel="库位筛选"
|
||||
:fields="queryFields"
|
||||
preference-key="locations-query"
|
||||
@search="applyFilters"
|
||||
/>
|
||||
<AdminPage as="div" class="location-page">
|
||||
<ListPageLayout aria-label="库位列表页面">
|
||||
<template #toolbar>
|
||||
<QueryToolbar
|
||||
v-model="filters"
|
||||
ariaLabel="库位筛选"
|
||||
:fields="queryFields"
|
||||
preference-key="locations-query"
|
||||
@search="applyFilters"
|
||||
/>
|
||||
</template>
|
||||
<template #state>
|
||||
<LoadErrorState
|
||||
v-if="warehouseError"
|
||||
title="仓库列表加载失败"
|
||||
:message="warehouseError.message"
|
||||
:loading="warehouseLoading"
|
||||
@retry="loadWarehouses"
|
||||
/>
|
||||
<el-alert v-else-if="!warehouseLoading && domesticWarehouses.length === 0" type="info" :closable="false" show-icon title="暂无可选国内仓">
|
||||
请先在仓库管理中建立国内仓,再维护库位。
|
||||
</el-alert>
|
||||
<LoadErrorState
|
||||
v-else-if="loadError"
|
||||
title="库位列表加载失败"
|
||||
:message="loadError.message"
|
||||
:loading="loading"
|
||||
@retry="loadLocations"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<el-alert v-if="warehouseError" type="error" :closable="false" show-icon class="state-alert">
|
||||
<template #title>仓库列表加载失败</template>
|
||||
<p>{{ warehouseError.message }}</p>
|
||||
<ApiErrorMeta :details="warehouseError" />
|
||||
<el-button size="small" @click="loadWarehouses()">重新加载仓库</el-button>
|
||||
</el-alert>
|
||||
<el-alert v-else-if="!warehouseLoading && domesticWarehouses.length === 0" type="info" :closable="false" show-icon title="暂无可选国内仓">
|
||||
请先在仓库管理中建立国内仓,再维护库位。
|
||||
</el-alert>
|
||||
<el-alert v-if="loadError" type="error" :closable="false" show-icon class="state-alert">
|
||||
<template #title>库位列表加载失败</template>
|
||||
<p>{{ loadError.message }}</p>
|
||||
<ApiErrorMeta :details="loadError" />
|
||||
<el-button size="small" @click="loadLocations()">重新查询</el-button>
|
||||
</el-alert>
|
||||
|
||||
<section class="surface-panel table-panel" aria-label="库位列表区域">
|
||||
<section v-if="!loadError" class="surface-panel table-panel" aria-label="库位列表区域">
|
||||
<DataTable
|
||||
v-model:page="page"
|
||||
v-model:page-size="pageSize"
|
||||
@@ -538,7 +549,6 @@ onMounted(() => {
|
||||
aria-label="库位列表"
|
||||
:empty-text="emptyDescription"
|
||||
>
|
||||
<template #toolbar-start><div><h2>库位列表</h2><p>共 {{ total }} 个库位</p></div></template>
|
||||
<template #toolbar-actions><el-button v-if="access.can('platform:location:create')" type="primary" @click="openCreate"><Plus :size="16" />新增库位</el-button></template>
|
||||
<template #actions="{ row }">
|
||||
<div class="table-actions location-actions">
|
||||
@@ -558,7 +568,7 @@ onMounted(() => {
|
||||
:disabled="loading || actionLoadingIds.has(String((row as PlatformLocationResource).id))"
|
||||
@command="handleMoreAction(row as PlatformLocationResource, String($event))"
|
||||
>
|
||||
<el-button link type="primary" aria-label="更多库位操作"><MoreHorizontal :size="16" />更多</el-button>
|
||||
<el-button link type="primary" aria-label="更多库位操作" title="更多库位操作"><MoreHorizontal :size="16" /></el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canChangeStatus(row as PlatformLocationResource)" command="status">
|
||||
@@ -610,18 +620,22 @@ onMounted(() => {
|
||||
</template>
|
||||
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 个库位</span></template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</section>
|
||||
</ListPageLayout>
|
||||
|
||||
<el-drawer
|
||||
<AppDrawer
|
||||
v-model="drawerOpen"
|
||||
:title="drawerTitle"
|
||||
size="min(620px, 100vw)"
|
||||
class="business-drawer location-drawer"
|
||||
size="min(620px, 94vw)"
|
||||
class="location-drawer"
|
||||
:loading="drawerLoading"
|
||||
:confirm-loading="saving"
|
||||
:show-confirm="false"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="!saving"
|
||||
:show-close="!saving"
|
||||
>
|
||||
<div v-loading="drawerLoading" class="drawer-content">
|
||||
<div class="drawer-content">
|
||||
<el-alert v-if="drawerError" type="error" :closable="false" show-icon title="库位详情加载失败">
|
||||
<p>{{ drawerError.message }}</p>
|
||||
<ApiErrorMeta :details="drawerError" />
|
||||
@@ -689,9 +703,7 @@ onMounted(() => {
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<section class="form-section">
|
||||
<h3>库位标识</h3>
|
||||
<p class="section-description">库位编码在当前仓库内唯一;编辑后不能移动到其他仓库。</p>
|
||||
<FormSection title="库位标识" description="库位编码在当前仓库内唯一;编辑后不能移动到其他仓库。">
|
||||
<div class="form-grid two-cols">
|
||||
<el-form-item label="库位编码" prop="locationCode" required>
|
||||
<el-input v-model.trim="form.locationCode" maxlength="50" placeholder="例如 A1-01" />
|
||||
@@ -706,10 +718,9 @@ onMounted(() => {
|
||||
<el-input v-model.trim="form.zoneName" maxlength="100" placeholder="例如 常规区" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</section>
|
||||
</FormSection>
|
||||
|
||||
<section class="form-section">
|
||||
<h3>资源属性</h3>
|
||||
<FormSection title="资源属性">
|
||||
<div class="form-grid two-cols">
|
||||
<el-form-item label="库位类型" prop="locationType" required>
|
||||
<el-select v-model="form.locationType" placeholder="请选择库位类型">
|
||||
@@ -735,25 +746,24 @@ onMounted(() => {
|
||||
<el-tag :type="statusMeta[form.status].type">{{ statusMeta[form.status].label }}</el-tag>
|
||||
<small>状态只能通过列表中的启停操作变更。</small>
|
||||
</div>
|
||||
</section>
|
||||
</FormSection>
|
||||
|
||||
<section class="form-section">
|
||||
<h3>备注</h3>
|
||||
<FormSection title="备注">
|
||||
<el-form-item label="内部说明">
|
||||
<el-input v-model.trim="form.remark" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="请输入库位位置、使用限制或其他说明" />
|
||||
</el-form-item>
|
||||
</section>
|
||||
</FormSection>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="drawer-footer">
|
||||
<el-button :disabled="saving" @click="drawerOpen = false">{{ drawerMode === 'view' ? '关闭' : '取消' }}</el-button>
|
||||
<el-button v-if="drawerMode !== 'view'" type="primary" :loading="saving" @click="saveLocation">保存库位</el-button>
|
||||
<el-button v-if="drawerMode !== 'view'" type="primary" :loading="saving" @click="saveLocation"><Save :size="16" />保存库位</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</AppDrawer>
|
||||
</AdminPage>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -154,7 +154,11 @@ describe('PalletsView', () => {
|
||||
expect(wrapper.text()).toContain('8 kg')
|
||||
expect(wrapper.text()).toContain('黄色')
|
||||
expect(wrapper.text()).not.toContain('更新时间')
|
||||
expect(wrapper.text()).toContain('托盘列表')
|
||||
const tableToolbar = wrapper.find('.table-panel .data-table__toolbar')
|
||||
expect(tableToolbar.exists()).toBe(true)
|
||||
expect(tableToolbar.text()).toContain('新增托盘')
|
||||
expect(tableToolbar.text()).not.toContain('托盘列表')
|
||||
expect(wrapper.find('.data-table__pagination-left').text()).toContain('共 1 个托盘')
|
||||
expect(wrapper.text()).not.toContain('启停托盘')
|
||||
expect(wrapper.text()).not.toContain('全部状态')
|
||||
expect(wrapper.text()).toContain('全部托盘类型')
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { Boxes, Eye, Pencil, Plus, Trash2, Warehouse as WarehouseIcon } from '@lucide/vue'
|
||||
import { Boxes, Eye, Pencil, Plus, Save, Trash2, Warehouse as WarehouseIcon } from '@lucide/vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useUnsavedWorkRegistration } from '@/core/unsaved-work/useUnsavedWorkRegistration'
|
||||
import { listAllPlatformWarehouses, type PlatformWarehouseResource } from '@/modules/warehouses'
|
||||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import AdminPage from '@/shared/components/AdminPage.vue'
|
||||
import AppDrawer from '@/shared/components/AppDrawer.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.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 {
|
||||
@@ -368,35 +372,38 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="pallet-page">
|
||||
<QueryToolbar
|
||||
v-model="filters"
|
||||
class="surface-panel pallet-filter-toolbar"
|
||||
ariaLabel="托盘筛选"
|
||||
:fields="queryFields"
|
||||
preference-key="pallets-query"
|
||||
:search-on-reset="false"
|
||||
@search="applyFilters"
|
||||
@reset="resetFilters"
|
||||
/>
|
||||
<AdminPage as="div" class="pallet-page">
|
||||
<ListPageLayout aria-label="托盘列表页面">
|
||||
<template #toolbar>
|
||||
<QueryToolbar
|
||||
v-model="filters"
|
||||
class="surface-panel pallet-filter-toolbar"
|
||||
ariaLabel="托盘筛选"
|
||||
:fields="queryFields"
|
||||
preference-key="pallets-query"
|
||||
:search-on-reset="false"
|
||||
@search="applyFilters"
|
||||
@reset="resetFilters"
|
||||
/>
|
||||
</template>
|
||||
<template #state>
|
||||
<LoadErrorState
|
||||
v-if="warehouseError"
|
||||
title="仓库列表暂时无法加载"
|
||||
:message="warehouseError.message"
|
||||
:loading="warehouseLoading"
|
||||
@retry="loadWarehouses"
|
||||
/>
|
||||
<LoadErrorState
|
||||
v-else-if="loadError"
|
||||
title="托盘列表暂时无法加载"
|
||||
:message="loadError.message"
|
||||
:loading="loading"
|
||||
@retry="loadPallets"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<LoadErrorState
|
||||
v-if="warehouseError"
|
||||
title="仓库列表暂时无法加载"
|
||||
:message="warehouseError.message"
|
||||
:loading="warehouseLoading"
|
||||
@retry="loadWarehouses"
|
||||
/>
|
||||
|
||||
<LoadErrorState
|
||||
v-if="loadError"
|
||||
title="托盘列表暂时无法加载"
|
||||
:message="loadError.message"
|
||||
:loading="loading"
|
||||
@retry="loadPallets"
|
||||
/>
|
||||
|
||||
<section class="table-panel surface-panel" aria-label="托盘列表区域">
|
||||
<section v-if="!loadError" class="table-panel surface-panel" aria-label="托盘列表区域">
|
||||
<DataTable
|
||||
v-model:page="page"
|
||||
v-model:page-size="pageSize"
|
||||
@@ -409,7 +416,6 @@ onMounted(() => {
|
||||
:empty-text="filtered ? '暂无符合筛选条件的托盘' : '暂无托盘数据'"
|
||||
aria-label="托盘列表"
|
||||
>
|
||||
<template #toolbar-start><div><h2>托盘列表</h2><p>共 {{ total }} 个托盘</p></div></template>
|
||||
<template #toolbar-actions><el-button v-if="access.can('platform:pallet:create')" type="primary" @click="openCreate"><Plus :size="16" />新增托盘</el-button></template>
|
||||
<template #actions="{ row }">
|
||||
<div class="table-actions pallet-row-actions">
|
||||
@@ -431,11 +437,13 @@ onMounted(() => {
|
||||
<template #capacity="{ row }"><strong>{{ formatCapacity((row as PlatformPalletResource).capacityCbm) }}</strong></template>
|
||||
<template #weight="{ row }"><strong>{{ formatWeight((row as PlatformPalletResource).weightKg) }}</strong></template>
|
||||
<template #remark="{ row }"><span class="remark-text">{{ (row as PlatformPalletResource).remark || '—' }}</span></template>
|
||||
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 个托盘</span></template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</section>
|
||||
</ListPageLayout>
|
||||
|
||||
<el-drawer v-model="detailOpen" title="托盘详情" size="520px" class="business-drawer">
|
||||
<div v-loading="detailLoading" class="detail-body">
|
||||
<AppDrawer v-model="detailOpen" title="托盘详情" size="min(520px, 94vw)" :loading="detailLoading" :show-confirm="false">
|
||||
<div class="detail-body">
|
||||
<template v-if="detail">
|
||||
<div class="detail-hero"><span><Boxes :size="22" /></span><div><h2>{{ detail.palletCode }}</h2><p>{{ detail.palletType }}</p></div></div>
|
||||
<h3 class="detail-section-title">归属信息</h3>
|
||||
@@ -460,7 +468,7 @@ onMounted(() => {
|
||||
</template>
|
||||
</div>
|
||||
<template #footer><el-button @click="detailOpen = false">关闭</el-button></template>
|
||||
</el-drawer>
|
||||
</AppDrawer>
|
||||
|
||||
<el-drawer v-model="editorOpen" size="560px" class="business-drawer pallet-editor-drawer" :close-on-click-modal="false">
|
||||
<template #header="{ titleId, titleClass }">
|
||||
@@ -473,11 +481,8 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="editor-form">
|
||||
<section class="editor-section" aria-labelledby="pallet-ownership-heading">
|
||||
<div class="editor-section-heading">
|
||||
<WarehouseIcon :size="18" aria-hidden="true" />
|
||||
<div><h3 id="pallet-ownership-heading">归属仓库</h3><p>托盘创建后固定归属于所选仓库,不支持跨仓移动。</p></div>
|
||||
</div>
|
||||
<FormSection class="editor-section" title="归属仓库" description="托盘创建后固定归属于所选仓库,不支持跨仓移动。" aria-labelledby="pallet-ownership-heading">
|
||||
<span id="pallet-ownership-heading" class="sr-only">归属仓库</span>
|
||||
<div v-if="form.id" class="editor-context">
|
||||
<div><strong>{{ editorWarehouse?.warehouseName || '当前仓库' }}</strong><span>{{ editorWarehouse?.warehouseCode || form.warehouseId }} · 平台公共资源</span></div>
|
||||
</div>
|
||||
@@ -491,13 +496,10 @@ onMounted(() => {
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</section>
|
||||
</FormSection>
|
||||
|
||||
<section class="editor-section" aria-labelledby="pallet-spec-heading">
|
||||
<div class="editor-section-heading">
|
||||
<Boxes :size="18" aria-hidden="true" />
|
||||
<div><h3 id="pallet-spec-heading">托盘规格</h3><p>编码由系统自动生成,请维护类型、容积、重量和颜色。</p></div>
|
||||
</div>
|
||||
<FormSection class="editor-section" title="托盘规格" description="编码由系统自动生成,请维护类型、容积、重量和颜色。" aria-labelledby="pallet-spec-heading">
|
||||
<span id="pallet-spec-heading" class="sr-only">托盘规格</span>
|
||||
<div class="editor-field-grid">
|
||||
<el-form-item label="托盘编码">
|
||||
<el-input :model-value="form.palletCode || '保存后自动生成'" disabled aria-label="托盘编码(系统生成)" />
|
||||
@@ -529,16 +531,16 @@ onMounted(() => {
|
||||
<el-form-item label="备注" prop="remark" class="editor-remark-field">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="可填写其他说明" />
|
||||
</el-form-item>
|
||||
</section>
|
||||
</FormSection>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="drawer-footer pallet-editor-footer">
|
||||
<span><i aria-hidden="true">*</i> 为必填项</span>
|
||||
<div><el-button :disabled="saving" @click="editorOpen = false">取消</el-button><el-button type="primary" :loading="saving" @click="savePallet">保存托盘</el-button></div>
|
||||
<div><el-button :disabled="saving" @click="editorOpen = false">取消</el-button><el-button type="primary" :loading="saving" @click="savePallet"><Save :size="16" />保存托盘</el-button></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</section>
|
||||
</AdminPage>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user