feat: add loc basic info page
| New file |
| | |
| | | import request from '@/utils/http' |
| | | |
| | | function normalizeText(value) { |
| | | return typeof value === 'string' ? value.trim() : value |
| | | } |
| | | |
| | | function normalizeIds(ids) { |
| | | if (Array.isArray(ids)) { |
| | | return ids |
| | | .map((id) => String(id).trim()) |
| | | .filter(Boolean) |
| | | .join(',') |
| | | } |
| | | if (ids === null || ids === undefined) { |
| | | return '' |
| | | } |
| | | return String(ids).trim() |
| | | } |
| | | |
| | | function normalizeNumber(value, fallback = void 0) { |
| | | if (value === '' || value === null || value === undefined) { |
| | | return fallback |
| | | } |
| | | const parsed = Number(value) |
| | | return Number.isNaN(parsed) ? fallback : parsed |
| | | } |
| | | |
| | | function normalizeTypeIds(typeIds = []) { |
| | | if (Array.isArray(typeIds)) { |
| | | return typeIds |
| | | .map((item) => normalizeNumber(item, void 0)) |
| | | .filter((item) => item !== void 0 && item !== null) |
| | | } |
| | | |
| | | if (typeof typeIds === 'string' && typeIds.trim()) { |
| | | return typeIds |
| | | .split(',') |
| | | .map((item) => normalizeNumber(item, void 0)) |
| | | .filter((item) => item !== void 0 && item !== null) |
| | | } |
| | | |
| | | return [] |
| | | } |
| | | |
| | | function filterParams(params = {}, ignoredKeys = []) { |
| | | return Object.fromEntries( |
| | | Object.entries(params) |
| | | .filter(([key, value]) => { |
| | | if (ignoredKeys.includes(key)) return false |
| | | if (value === undefined || value === null) return false |
| | | if (typeof value === 'string' && value.trim() === '') return false |
| | | return true |
| | | }) |
| | | .map(([key, value]) => [key, normalizeText(value)]) |
| | | ) |
| | | } |
| | | |
| | | export function buildLocPageParams(params = {}) { |
| | | return { |
| | | current: params.current || 1, |
| | | pageSize: params.pageSize || params.size || 20, |
| | | ...filterParams(params, ['current', 'pageSize', 'size']) |
| | | } |
| | | } |
| | | |
| | | export function buildLocSearchParams(params = {}) { |
| | | const searchParams = { |
| | | condition: normalizeText(params.condition), |
| | | warehouseId: |
| | | params.warehouseId !== undefined && params.warehouseId !== null && params.warehouseId !== '' |
| | | ? Number(params.warehouseId) |
| | | : void 0, |
| | | areaId: |
| | | params.areaId !== undefined && params.areaId !== null && params.areaId !== '' |
| | | ? Number(params.areaId) |
| | | : void 0, |
| | | code: normalizeText(params.code), |
| | | useStatus: normalizeText(params.useStatus), |
| | | row: |
| | | params.row !== undefined && params.row !== null && params.row !== '' |
| | | ? Number(params.row) |
| | | : void 0, |
| | | col: |
| | | params.col !== undefined && params.col !== null && params.col !== '' |
| | | ? Number(params.col) |
| | | : void 0, |
| | | lev: |
| | | params.lev !== undefined && params.lev !== null && params.lev !== '' |
| | | ? Number(params.lev) |
| | | : void 0, |
| | | channel: |
| | | params.channel !== undefined && params.channel !== null && params.channel !== '' |
| | | ? Number(params.channel) |
| | | : void 0, |
| | | status: |
| | | params.status !== undefined && params.status !== null && params.status !== '' |
| | | ? Number(params.status) |
| | | : void 0, |
| | | barcode: normalizeText(params.barcode), |
| | | memo: normalizeText(params.memo) |
| | | } |
| | | |
| | | return Object.fromEntries( |
| | | Object.entries(searchParams).filter(([, value]) => value !== '' && value !== void 0 && value !== null) |
| | | ) |
| | | } |
| | | |
| | | export function buildLocSavePayload(formData = {}) { |
| | | return { |
| | | ...(formData.id !== undefined && formData.id !== null && formData.id !== '' |
| | | ? { id: Number(formData.id) } |
| | | : {}), |
| | | ...(formData.version !== undefined && formData.version !== null && formData.version !== '' |
| | | ? { version: Number(formData.version) } |
| | | : {}), |
| | | ...(formData.warehouseId !== undefined && formData.warehouseId !== null && formData.warehouseId !== '' |
| | | ? { warehouseId: Number(formData.warehouseId) } |
| | | : {}), |
| | | ...(formData.areaId !== undefined && formData.areaId !== null && formData.areaId !== '' |
| | | ? { areaId: Number(formData.areaId) } |
| | | : {}), |
| | | code: normalizeText(formData.code) || '', |
| | | typeIds: normalizeTypeIds(formData.typeIds), |
| | | ...(formData.flagLogic !== undefined && formData.flagLogic !== null && formData.flagLogic !== '' |
| | | ? { flagLogic: Number(formData.flagLogic) } |
| | | : {}), |
| | | fucAtrrs: normalizeText(formData.fucAtrrs) || '', |
| | | barcode: normalizeText(formData.barcode) || '', |
| | | unit: normalizeText(formData.unit) || '', |
| | | ...(formData.length !== undefined && formData.length !== null && formData.length !== '' |
| | | ? { length: Number(formData.length) } |
| | | : {}), |
| | | ...(formData.height !== undefined && formData.height !== null && formData.height !== '' |
| | | ? { height: Number(formData.height) } |
| | | : {}), |
| | | ...(formData.width !== undefined && formData.width !== null && formData.width !== '' |
| | | ? { width: Number(formData.width) } |
| | | : {}), |
| | | ...(formData.row !== undefined && formData.row !== null && formData.row !== '' |
| | | ? { row: Number(formData.row) } |
| | | : {}), |
| | | ...(formData.col !== undefined && formData.col !== null && formData.col !== '' |
| | | ? { col: Number(formData.col) } |
| | | : {}), |
| | | ...(formData.lev !== undefined && formData.lev !== null && formData.lev !== '' |
| | | ? { lev: Number(formData.lev) } |
| | | : {}), |
| | | ...(formData.channel !== undefined && formData.channel !== null && formData.channel !== '' |
| | | ? { channel: Number(formData.channel) } |
| | | : {}), |
| | | ...(formData.maxParts !== undefined && formData.maxParts !== null && formData.maxParts !== '' |
| | | ? { maxParts: Number(formData.maxParts) } |
| | | : {}), |
| | | ...(formData.maxPack !== undefined && formData.maxPack !== null && formData.maxPack !== '' |
| | | ? { maxPack: Number(formData.maxPack) } |
| | | : {}), |
| | | useStatus: normalizeText(formData.useStatus) || 'O', |
| | | ...(formData.flagLabelMange !== undefined && formData.flagLabelMange !== null && formData.flagLabelMange !== '' |
| | | ? { flagLabelMange: Number(formData.flagLabelMange) } |
| | | : {}), |
| | | locAttrs: normalizeText(formData.locAttrs) || '', |
| | | status: |
| | | formData.status !== undefined && formData.status !== null && formData.status !== '' |
| | | ? Number(formData.status) |
| | | : 1, |
| | | memo: normalizeText(formData.memo) || '' |
| | | } |
| | | } |
| | | |
| | | export function fetchLocPage(params = {}) { |
| | | return request.post({ |
| | | url: '/loc/page', |
| | | params: buildLocPageParams(params) |
| | | }) |
| | | } |
| | | |
| | | export function fetchGetLocDetail(id) { |
| | | return request.get({ |
| | | url: `/loc/${id}` |
| | | }) |
| | | } |
| | | |
| | | export function fetchGetLocMany(ids) { |
| | | return request.post({ |
| | | url: `/loc/many/${normalizeIds(ids)}` |
| | | }) |
| | | } |
| | | |
| | | export function fetchSaveLoc(params = {}) { |
| | | return request.post({ |
| | | url: '/loc/save', |
| | | params: buildLocSavePayload(params) |
| | | }) |
| | | } |
| | | |
| | | export function fetchUpdateLoc(params = {}) { |
| | | return request.post({ |
| | | url: '/loc/update', |
| | | params: buildLocSavePayload(params) |
| | | }) |
| | | } |
| | | |
| | | export function fetchDeleteLoc(ids) { |
| | | return request.post({ |
| | | url: `/loc/remove/${normalizeIds(ids)}` |
| | | }) |
| | | } |
| | | |
| | | export function fetchLocQuery(condition = '') { |
| | | return request.post({ |
| | | url: '/loc/query', |
| | | params: { |
| | | condition: normalizeText(condition) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | export function fetchLocTypeList() { |
| | | return request.post({ |
| | | url: '/locType/list', |
| | | data: {} |
| | | }) |
| | | } |
| | | |
| | | export function fetchWarehouseList() { |
| | | return request.post({ |
| | | url: '/warehouse/list', |
| | | data: {} |
| | | }) |
| | | } |
| | | |
| | | export function fetchWarehouseAreasList() { |
| | | return request.post({ |
| | | url: '/warehouseAreas/list', |
| | | data: {} |
| | | }) |
| | | } |
| | | |
| | | export async function fetchExportLocReport(payload = {}, options = {}) { |
| | | return fetch(`${import.meta.env.VITE_API_URL}/loc/export`, { |
| | | method: 'POST', |
| | | headers: { |
| | | 'Content-Type': 'application/json', |
| | | ...(options.headers || {}) |
| | | }, |
| | | body: JSON.stringify(payload) |
| | | }) |
| | | } |
| | |
| | | basContainer: '/basic-info/bas-container', |
| | | warehouse: '/basic-info/warehouse', |
| | | warehouseAreas: '/basic-info/warehouse-areas', |
| | | loc: '/basic-info/loc', |
| | | warehouseStock: '/stock/warehouse-stock', |
| | | warehouseAreasItem: '/stock/warehouse-areas-item', |
| | | qlyInspect: '/manager/qly-inspect', |
| | |
| | | icon: 'ri:layout-grid-line', |
| | | keepAlive: false |
| | | } |
| | | }, |
| | | { |
| | | path: 'loc', |
| | | name: 'Loc', |
| | | component: () => import('@views/basic-info/loc/index.vue'), |
| | | meta: { |
| | | title: 'menu.loc', |
| | | icon: 'ri:map-pin-2-line', |
| | | keepAlive: false |
| | | } |
| | | } |
| | | ] |
| | | }, |
| New file |
| | |
| | | <template> |
| | | <div class="loc-page art-full-height"> |
| | | <ArtSearchBar |
| | | v-model="searchForm" |
| | | :items="searchItems" |
| | | :showExpand="true" |
| | | @search="handleSearch" |
| | | @reset="handleReset" |
| | | /> |
| | | |
| | | <ElCard class="art-table-card"> |
| | | <ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData"> |
| | | <template #left> |
| | | <ElSpace wrap> |
| | | <ElButton v-auth="'add'" @click="showDialog('add')" v-ripple>新增库位</ElButton> |
| | | <ElButton |
| | | v-auth="'delete'" |
| | | type="danger" |
| | | :disabled="selectedRows.length === 0" |
| | | @click="handleBatchDelete" |
| | | v-ripple |
| | | > |
| | | 批量删除 |
| | | </ElButton> |
| | | <ListExportPrint |
| | | class="inline-flex" |
| | | :preview-visible="previewVisible" |
| | | @update:previewVisible="handlePreviewVisibleChange" |
| | | :report-title="reportTitle" |
| | | :selected-rows="selectedRows" |
| | | :query-params="reportQueryParams" |
| | | :columns="columns" |
| | | :preview-rows="previewRows" |
| | | :preview-meta="resolvedPreviewMeta" |
| | | :total="pagination.total" |
| | | :disabled="loading" |
| | | @export="handleExport" |
| | | @print="handlePrint" |
| | | /> |
| | | </ElSpace> |
| | | </template> |
| | | </ArtTableHeader> |
| | | |
| | | <ArtTable |
| | | :loading="loading" |
| | | :data="data" |
| | | :columns="columns" |
| | | :pagination="pagination" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination:size-change="handleSizeChange" |
| | | @pagination:current-change="handleCurrentChange" |
| | | /> |
| | | |
| | | <LocDialog |
| | | v-model:visible="dialogVisible" |
| | | :dialog-type="dialogType" |
| | | :loc-data="currentLocData" |
| | | :warehouse-options="warehouseOptions" |
| | | :area-options="areaOptions" |
| | | :loc-type-options="locTypeOptions" |
| | | @submit="handleDialogSubmit" |
| | | /> |
| | | |
| | | <LocDetailDrawer |
| | | v-model:visible="detailDrawerVisible" |
| | | :loading="detailLoading" |
| | | :detail="detailData" |
| | | /> |
| | | </ElCard> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, onMounted, ref } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { useUserStore } from '@/store/modules/user' |
| | | import { useAuth } from '@/hooks/core/useAuth' |
| | | import { useTable } from '@/hooks/core/useTable' |
| | | import { useCrudPage } from '@/views/system/common/useCrudPage' |
| | | import { usePrintExportPage } from '@/views/system/common/usePrintExportPage' |
| | | import ListExportPrint from '@/components/biz/list-export-print/index.vue' |
| | | import { defaultResponseAdapter } from '@/utils/table/tableUtils' |
| | | import { guardRequestWithMessage } from '@/utils/sys/requestGuard' |
| | | import { fetchWarehouseAreasList, fetchWarehouseList } from '@/api/warehouse-areas' |
| | | import { |
| | | fetchDeleteLoc, |
| | | fetchExportLocReport, |
| | | fetchGetLocDetail, |
| | | fetchGetLocMany, |
| | | fetchLocPage, |
| | | fetchLocTypeList, |
| | | fetchSaveLoc, |
| | | fetchUpdateLoc |
| | | } from '@/api/loc' |
| | | import LocDialog from './modules/loc-dialog.vue' |
| | | import LocDetailDrawer from './modules/loc-detail-drawer.vue' |
| | | import { createLocTableColumns } from './locTable.columns' |
| | | import { |
| | | buildLocDialogModel, |
| | | buildLocPageQueryParams, |
| | | buildLocPrintRows, |
| | | buildLocReportMeta, |
| | | buildLocSavePayload, |
| | | buildLocSearchParams, |
| | | createLocSearchState, |
| | | getLocPaginationKey, |
| | | getLocStatusOptions, |
| | | getLocUseStatusOptions, |
| | | normalizeLocListRow, |
| | | resolveLocAreaOptions, |
| | | resolveLocTypeOptions, |
| | | resolveLocWarehouseOptions, |
| | | LOC_REPORT_STYLE, |
| | | LOC_REPORT_TITLE |
| | | } from './locPage.helpers' |
| | | |
| | | defineOptions({ name: 'Loc' }) |
| | | |
| | | const { hasAuth } = useAuth() |
| | | const userStore = useUserStore() |
| | | |
| | | const searchForm = ref(createLocSearchState()) |
| | | const detailDrawerVisible = ref(false) |
| | | const detailLoading = ref(false) |
| | | const detailData = ref({}) |
| | | const warehouseOptions = ref([]) |
| | | const areaOptions = ref([]) |
| | | const locTypeOptions = ref([]) |
| | | let handleDeleteAction = null |
| | | |
| | | const reportTitle = LOC_REPORT_TITLE |
| | | const reportQueryParams = computed(() => buildLocSearchParams(searchForm.value)) |
| | | |
| | | const searchItems = computed(() => [ |
| | | { |
| | | label: '关键字', |
| | | key: 'condition', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入库位号/容器编码/备注' |
| | | } |
| | | }, |
| | | { |
| | | label: '仓库', |
| | | key: 'warehouseId', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | filterable: true, |
| | | options: warehouseOptions.value |
| | | } |
| | | }, |
| | | { |
| | | label: '库区', |
| | | key: 'areaId', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | filterable: true, |
| | | options: areaOptions.value.filter((item) => { |
| | | if (!searchForm.value.warehouseId) { |
| | | return true |
| | | } |
| | | if (item?.warehouseId === undefined || item?.warehouseId === null) { |
| | | return true |
| | | } |
| | | return Number(item.warehouseId) === Number(searchForm.value.warehouseId) |
| | | }) |
| | | } |
| | | }, |
| | | { |
| | | label: '库位号', |
| | | key: 'code', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入库位号' |
| | | } |
| | | }, |
| | | { |
| | | label: '使用状态', |
| | | key: 'useStatus', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | filterable: true, |
| | | options: getLocUseStatusOptions() |
| | | } |
| | | }, |
| | | { |
| | | label: '排', |
| | | key: 'row', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入排' |
| | | } |
| | | }, |
| | | { |
| | | label: '列', |
| | | key: 'col', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入列' |
| | | } |
| | | }, |
| | | { |
| | | label: '层', |
| | | key: 'lev', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入层' |
| | | } |
| | | }, |
| | | { |
| | | label: '巷道', |
| | | key: 'channel', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入巷道' |
| | | } |
| | | }, |
| | | { |
| | | label: '状态', |
| | | key: 'status', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | options: getLocStatusOptions() |
| | | } |
| | | }, |
| | | { |
| | | label: '容器编码', |
| | | key: 'barcode', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入容器编码' |
| | | } |
| | | }, |
| | | { |
| | | label: '备注', |
| | | key: 'memo', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入备注' |
| | | } |
| | | } |
| | | ]) |
| | | |
| | | async function openDetail(row) { |
| | | detailDrawerVisible.value = true |
| | | detailLoading.value = true |
| | | try { |
| | | const detail = await guardRequestWithMessage(fetchGetLocDetail(row.id), {}, { |
| | | timeoutMessage: '库位详情加载超时,已停止等待' |
| | | }) |
| | | detailData.value = normalizeLocListRow(detail) |
| | | } catch (error) { |
| | | detailDrawerVisible.value = false |
| | | detailData.value = {} |
| | | ElMessage.error(error?.message || '获取库位详情失败') |
| | | } finally { |
| | | detailLoading.value = false |
| | | } |
| | | } |
| | | |
| | | async function openEditDialog(row) { |
| | | try { |
| | | const detail = await guardRequestWithMessage(fetchGetLocDetail(row.id), {}, { |
| | | timeoutMessage: '库位详情加载超时,已停止等待' |
| | | }) |
| | | showDialog('edit', detail) |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || '获取库位详情失败') |
| | | } |
| | | } |
| | | |
| | | const { |
| | | columns, |
| | | columnChecks, |
| | | data, |
| | | loading, |
| | | pagination, |
| | | getData, |
| | | replaceSearchParams, |
| | | resetSearchParams, |
| | | handleSizeChange, |
| | | handleCurrentChange, |
| | | refreshData, |
| | | refreshCreate, |
| | | refreshUpdate, |
| | | refreshRemove |
| | | } = useTable({ |
| | | core: { |
| | | apiFn: fetchLocPage, |
| | | apiParams: buildLocPageQueryParams(searchForm.value), |
| | | paginationKey: getLocPaginationKey(), |
| | | columnsFactory: () => |
| | | createLocTableColumns({ |
| | | handleView: openDetail, |
| | | handleEdit: hasAuth('update') ? openEditDialog : null, |
| | | handleDelete: hasAuth('delete') ? (row) => handleDeleteAction?.(row) : null, |
| | | canEdit: hasAuth('update'), |
| | | canDelete: hasAuth('delete') |
| | | }) |
| | | }, |
| | | transform: { |
| | | dataTransformer: (records) => { |
| | | if (!Array.isArray(records)) { |
| | | return [] |
| | | } |
| | | return records.map((item) => normalizeLocListRow(item)) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | const { |
| | | dialogVisible, |
| | | dialogType, |
| | | currentRecord: currentLocData, |
| | | selectedRows, |
| | | handleSelectionChange, |
| | | showDialog, |
| | | handleDialogSubmit, |
| | | handleDelete, |
| | | handleBatchDelete |
| | | } = useCrudPage({ |
| | | createEmptyModel: () => buildLocDialogModel(), |
| | | buildEditModel: (record) => buildLocDialogModel(record), |
| | | buildSavePayload: (formData) => buildLocSavePayload(formData), |
| | | saveRequest: fetchSaveLoc, |
| | | updateRequest: fetchUpdateLoc, |
| | | deleteRequest: fetchDeleteLoc, |
| | | entityName: '库位', |
| | | resolveRecordLabel: (record) => record?.code || record?.barcode || record?.id, |
| | | refreshCreate, |
| | | refreshUpdate, |
| | | refreshRemove |
| | | }) |
| | | handleDeleteAction = handleDelete |
| | | |
| | | const buildPreviewDialogMeta = (rows) => { |
| | | const now = new Date() |
| | | return { |
| | | reportTitle, |
| | | reportDate: now.toLocaleDateString('zh-CN'), |
| | | printedAt: now.toLocaleString('zh-CN', { hour12: false }), |
| | | operator: userStore.getUserInfo?.name || userStore.getUserInfo?.username || '', |
| | | count: rows.length |
| | | } |
| | | } |
| | | |
| | | const resolvePrintRecords = async (payload) => { |
| | | const response = Array.isArray(payload?.ids) && payload.ids.length > 0 |
| | | ? await fetchGetLocMany(payload.ids) |
| | | : await fetchLocPage({ |
| | | ...reportQueryParams.value, |
| | | current: 1, |
| | | pageSize: Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20 |
| | | }) |
| | | return defaultResponseAdapter(response).records |
| | | } |
| | | |
| | | const { |
| | | previewVisible, |
| | | previewRows, |
| | | previewMeta, |
| | | handlePreviewVisibleChange, |
| | | handleExport, |
| | | handlePrint |
| | | } = usePrintExportPage({ |
| | | downloadFileName: 'loc.xlsx', |
| | | requestExport: (payload) => |
| | | fetchExportLocReport(payload, { |
| | | headers: { |
| | | Authorization: userStore.accessToken || '' |
| | | } |
| | | }), |
| | | resolvePrintRecords, |
| | | buildPreviewRows: (records) => buildLocPrintRows(records), |
| | | buildPreviewMeta: (rows) => buildPreviewDialogMeta(rows) |
| | | }) |
| | | |
| | | const resolvedPreviewMeta = computed(() => |
| | | buildLocReportMeta({ |
| | | previewMeta: previewMeta.value, |
| | | count: previewRows.value.length, |
| | | titleAlign: LOC_REPORT_STYLE.titleAlign, |
| | | titleLevel: LOC_REPORT_STYLE.titleLevel |
| | | }) |
| | | ) |
| | | |
| | | async function loadWarehouseOptions() { |
| | | const response = await guardRequestWithMessage(fetchWarehouseList(), [], { |
| | | timeoutMessage: '仓库选项加载超时,已停止等待' |
| | | }) |
| | | warehouseOptions.value = resolveLocWarehouseOptions(defaultResponseAdapter(response).records) |
| | | } |
| | | |
| | | async function loadAreaOptions() { |
| | | const response = await guardRequestWithMessage(fetchWarehouseAreasList(), [], { |
| | | timeoutMessage: '库区选项加载超时,已停止等待' |
| | | }) |
| | | areaOptions.value = resolveLocAreaOptions(defaultResponseAdapter(response).records) |
| | | } |
| | | |
| | | async function loadLocTypeOptions() { |
| | | const response = await guardRequestWithMessage(fetchLocTypeList(), [], { |
| | | timeoutMessage: '库位类型选项加载超时,已停止等待' |
| | | }) |
| | | locTypeOptions.value = resolveLocTypeOptions(defaultResponseAdapter(response).records) |
| | | } |
| | | |
| | | function handleSearch(params) { |
| | | replaceSearchParams(buildLocSearchParams(params)) |
| | | getData() |
| | | } |
| | | |
| | | function handleReset() { |
| | | Object.assign(searchForm.value, createLocSearchState()) |
| | | resetSearchParams() |
| | | } |
| | | |
| | | onMounted(async () => { |
| | | await Promise.all([loadWarehouseOptions(), loadAreaOptions(), loadLocTypeOptions()]) |
| | | }) |
| | | </script> |
| New file |
| | |
| | | const STATUS_META = { |
| | | 1: { text: '正常', type: 'success', bool: true }, |
| | | 0: { text: '冻结', type: 'danger', bool: false } |
| | | } |
| | | |
| | | const USE_STATUS_META = { |
| | | O: { text: '空库', type: 'success' }, |
| | | D: { text: '空板', type: 'info' }, |
| | | R: { text: '预约出库', type: 'warning' }, |
| | | S: { text: '预约入库', type: 'warning' }, |
| | | X: { text: '禁用', type: 'danger' }, |
| | | F: { text: '在库', type: 'primary' } |
| | | } |
| | | |
| | | export const LOC_REPORT_TITLE = '库位报表' |
| | | export const LOC_REPORT_STYLE = { |
| | | titleAlign: 'center', |
| | | titleLevel: 'strong', |
| | | orientation: 'portrait', |
| | | density: 'compact', |
| | | showSequence: true |
| | | } |
| | | |
| | | function normalizeText(value) { |
| | | return String(value ?? '').trim() |
| | | } |
| | | |
| | | function normalizeNumber(value, fallback = void 0) { |
| | | if (value === '' || value === null || value === undefined) { |
| | | return fallback |
| | | } |
| | | const parsed = Number(value) |
| | | return Number.isNaN(parsed) ? fallback : parsed |
| | | } |
| | | |
| | | function normalizeFlagText(value) { |
| | | if (value === 1 || value === '1' || value === true || value === '是') { |
| | | return '是' |
| | | } |
| | | if (value === 0 || value === '0' || value === false || value === '否') { |
| | | return '否' |
| | | } |
| | | return normalizeText(value) || '--' |
| | | } |
| | | |
| | | function normalizeTypeIds(typeIds = []) { |
| | | if (Array.isArray(typeIds)) { |
| | | return typeIds |
| | | .map((item) => normalizeNumber(item, void 0)) |
| | | .filter((item) => item !== void 0 && item !== null) |
| | | } |
| | | |
| | | if (typeof typeIds === 'string' && typeIds.trim()) { |
| | | return typeIds |
| | | .split(',') |
| | | .map((item) => normalizeNumber(item, void 0)) |
| | | .filter((item) => item !== void 0 && item !== null) |
| | | } |
| | | |
| | | return [] |
| | | } |
| | | |
| | | export function createLocSearchState() { |
| | | return { |
| | | condition: '', |
| | | warehouseId: '', |
| | | areaId: '', |
| | | code: '', |
| | | useStatus: '', |
| | | row: '', |
| | | col: '', |
| | | lev: '', |
| | | channel: '', |
| | | status: '', |
| | | barcode: '', |
| | | memo: '' |
| | | } |
| | | } |
| | | |
| | | export function createLocFormState() { |
| | | return { |
| | | id: void 0, |
| | | version: void 0, |
| | | warehouseId: void 0, |
| | | areaId: void 0, |
| | | code: '', |
| | | typeIds: [], |
| | | flagLogic: 0, |
| | | fucAtrrs: '', |
| | | barcode: '', |
| | | unit: '', |
| | | length: void 0, |
| | | height: void 0, |
| | | width: void 0, |
| | | row: void 0, |
| | | col: void 0, |
| | | lev: void 0, |
| | | channel: void 0, |
| | | maxParts: void 0, |
| | | maxPack: void 0, |
| | | useStatus: 'O', |
| | | flagLabelMange: 0, |
| | | locAttrs: '', |
| | | status: 1, |
| | | memo: '' |
| | | } |
| | | } |
| | | |
| | | export function getLocPaginationKey() { |
| | | return { |
| | | current: 'current', |
| | | size: 'pageSize' |
| | | } |
| | | } |
| | | |
| | | export function getLocStatusOptions() { |
| | | return [ |
| | | { label: '正常', value: 1 }, |
| | | { label: '冻结', value: 0 } |
| | | ] |
| | | } |
| | | |
| | | export function getLocUseStatusOptions() { |
| | | return [ |
| | | { label: '空库', value: 'O' }, |
| | | { label: '空板', value: 'D' }, |
| | | { label: '预约出库', value: 'R' }, |
| | | { label: '预约入库', value: 'S' }, |
| | | { label: '禁用', value: 'X' }, |
| | | { label: '在库', value: 'F' } |
| | | ] |
| | | } |
| | | |
| | | export function getLocBinaryOptions() { |
| | | return [ |
| | | { label: '否', value: 0 }, |
| | | { label: '是', value: 1 } |
| | | ] |
| | | } |
| | | |
| | | export function getLocStatusMeta(status) { |
| | | if (status === true || Number(status) === 1) { |
| | | return STATUS_META[1] |
| | | } |
| | | if (status === false || Number(status) === 0) { |
| | | return STATUS_META[0] |
| | | } |
| | | return { text: '未知', type: 'info', bool: false } |
| | | } |
| | | |
| | | export function getLocUseStatusMeta(useStatus) { |
| | | if (!useStatus) { |
| | | return { text: '未知', type: 'info' } |
| | | } |
| | | return USE_STATUS_META[String(useStatus).trim()] || { text: String(useStatus), type: 'info' } |
| | | } |
| | | |
| | | export function buildLocSearchParams(params = {}) { |
| | | const searchParams = { |
| | | condition: normalizeText(params.condition), |
| | | warehouseId: |
| | | params.warehouseId !== undefined && params.warehouseId !== null && params.warehouseId !== '' |
| | | ? Number(params.warehouseId) |
| | | : void 0, |
| | | areaId: |
| | | params.areaId !== undefined && params.areaId !== null && params.areaId !== '' |
| | | ? Number(params.areaId) |
| | | : void 0, |
| | | code: normalizeText(params.code), |
| | | useStatus: normalizeText(params.useStatus), |
| | | row: |
| | | params.row !== undefined && params.row !== null && params.row !== '' |
| | | ? Number(params.row) |
| | | : void 0, |
| | | col: |
| | | params.col !== undefined && params.col !== null && params.col !== '' |
| | | ? Number(params.col) |
| | | : void 0, |
| | | lev: |
| | | params.lev !== undefined && params.lev !== null && params.lev !== '' |
| | | ? Number(params.lev) |
| | | : void 0, |
| | | channel: |
| | | params.channel !== undefined && params.channel !== null && params.channel !== '' |
| | | ? Number(params.channel) |
| | | : void 0, |
| | | status: |
| | | params.status !== undefined && params.status !== null && params.status !== '' |
| | | ? Number(params.status) |
| | | : void 0, |
| | | barcode: normalizeText(params.barcode), |
| | | memo: normalizeText(params.memo) |
| | | } |
| | | |
| | | return Object.fromEntries( |
| | | Object.entries(searchParams).filter(([, value]) => value !== '' && value !== void 0 && value !== null) |
| | | ) |
| | | } |
| | | |
| | | export function buildLocPageQueryParams(params = {}) { |
| | | return { |
| | | current: params.current || 1, |
| | | pageSize: params.pageSize || params.size || 20, |
| | | ...buildLocSearchParams(params) |
| | | } |
| | | } |
| | | |
| | | export function buildLocSavePayload(formData = {}) { |
| | | return { |
| | | ...(formData.id !== undefined && formData.id !== null && formData.id !== '' |
| | | ? { id: Number(formData.id) } |
| | | : {}), |
| | | ...(formData.version !== undefined && formData.version !== null && formData.version !== '' |
| | | ? { version: Number(formData.version) } |
| | | : {}), |
| | | ...(formData.warehouseId !== undefined && formData.warehouseId !== null && formData.warehouseId !== '' |
| | | ? { warehouseId: Number(formData.warehouseId) } |
| | | : {}), |
| | | ...(formData.areaId !== undefined && formData.areaId !== null && formData.areaId !== '' |
| | | ? { areaId: Number(formData.areaId) } |
| | | : {}), |
| | | code: normalizeText(formData.code) || '', |
| | | typeIds: normalizeTypeIds(formData.typeIds), |
| | | ...(formData.flagLogic !== undefined && formData.flagLogic !== null && formData.flagLogic !== '' |
| | | ? { flagLogic: Number(formData.flagLogic) } |
| | | : {}), |
| | | fucAtrrs: normalizeText(formData.fucAtrrs) || '', |
| | | barcode: normalizeText(formData.barcode) || '', |
| | | unit: normalizeText(formData.unit) || '', |
| | | ...(formData.length !== undefined && formData.length !== null && formData.length !== '' |
| | | ? { length: Number(formData.length) } |
| | | : {}), |
| | | ...(formData.height !== undefined && formData.height !== null && formData.height !== '' |
| | | ? { height: Number(formData.height) } |
| | | : {}), |
| | | ...(formData.width !== undefined && formData.width !== null && formData.width !== '' |
| | | ? { width: Number(formData.width) } |
| | | : {}), |
| | | ...(formData.row !== undefined && formData.row !== null && formData.row !== '' |
| | | ? { row: Number(formData.row) } |
| | | : {}), |
| | | ...(formData.col !== undefined && formData.col !== null && formData.col !== '' |
| | | ? { col: Number(formData.col) } |
| | | : {}), |
| | | ...(formData.lev !== undefined && formData.lev !== null && formData.lev !== '' |
| | | ? { lev: Number(formData.lev) } |
| | | : {}), |
| | | ...(formData.channel !== undefined && formData.channel !== null && formData.channel !== '' |
| | | ? { channel: Number(formData.channel) } |
| | | : {}), |
| | | ...(formData.maxParts !== undefined && formData.maxParts !== null && formData.maxParts !== '' |
| | | ? { maxParts: Number(formData.maxParts) } |
| | | : {}), |
| | | ...(formData.maxPack !== undefined && formData.maxPack !== null && formData.maxPack !== '' |
| | | ? { maxPack: Number(formData.maxPack) } |
| | | : {}), |
| | | useStatus: normalizeText(formData.useStatus) || 'O', |
| | | ...(formData.flagLabelMange !== undefined && formData.flagLabelMange !== null && formData.flagLabelMange !== '' |
| | | ? { flagLabelMange: Number(formData.flagLabelMange) } |
| | | : {}), |
| | | locAttrs: normalizeText(formData.locAttrs) || '', |
| | | status: |
| | | formData.status !== undefined && formData.status !== null && formData.status !== '' |
| | | ? Number(formData.status) |
| | | : 1, |
| | | memo: normalizeText(formData.memo) || '' |
| | | } |
| | | } |
| | | |
| | | export function buildLocDialogModel(record = {}) { |
| | | return { |
| | | ...createLocFormState(), |
| | | ...(record.id !== undefined && record.id !== null && record.id !== '' ? { id: Number(record.id) } : {}), |
| | | ...(record.version !== undefined && record.version !== null && record.version !== '' |
| | | ? { version: Number(record.version) } |
| | | : {}), |
| | | warehouseId: |
| | | record.warehouseId !== undefined && record.warehouseId !== null && record.warehouseId !== '' |
| | | ? Number(record.warehouseId) |
| | | : void 0, |
| | | areaId: |
| | | record.areaId !== undefined && record.areaId !== null && record.areaId !== '' |
| | | ? Number(record.areaId) |
| | | : void 0, |
| | | code: normalizeText(record.code || ''), |
| | | typeIds: normalizeTypeIds(record.typeIds ?? record.type ?? ''), |
| | | flagLogic: |
| | | record.flagLogic !== undefined && record.flagLogic !== null && record.flagLogic !== '' |
| | | ? Number(record.flagLogic) |
| | | : 0, |
| | | fucAtrrs: normalizeText(record.fucAtrrs || ''), |
| | | barcode: normalizeText(record.barcode || ''), |
| | | unit: normalizeText(record.unit || ''), |
| | | length: |
| | | record.length !== undefined && record.length !== null && record.length !== '' |
| | | ? Number(record.length) |
| | | : void 0, |
| | | height: |
| | | record.height !== undefined && record.height !== null && record.height !== '' |
| | | ? Number(record.height) |
| | | : void 0, |
| | | width: |
| | | record.width !== undefined && record.width !== null && record.width !== '' |
| | | ? Number(record.width) |
| | | : void 0, |
| | | row: |
| | | record.row !== undefined && record.row !== null && record.row !== '' |
| | | ? Number(record.row) |
| | | : void 0, |
| | | col: |
| | | record.col !== undefined && record.col !== null && record.col !== '' |
| | | ? Number(record.col) |
| | | : void 0, |
| | | lev: |
| | | record.lev !== undefined && record.lev !== null && record.lev !== '' |
| | | ? Number(record.lev) |
| | | : void 0, |
| | | channel: |
| | | record.channel !== undefined && record.channel !== null && record.channel !== '' |
| | | ? Number(record.channel) |
| | | : void 0, |
| | | maxParts: |
| | | record.maxParts !== undefined && record.maxParts !== null && record.maxParts !== '' |
| | | ? Number(record.maxParts) |
| | | : void 0, |
| | | maxPack: |
| | | record.maxPack !== undefined && record.maxPack !== null && record.maxPack !== '' |
| | | ? Number(record.maxPack) |
| | | : void 0, |
| | | useStatus: normalizeText(record.useStatus || 'O') || 'O', |
| | | flagLabelMange: |
| | | record.flagLabelMange !== undefined && record.flagLabelMange !== null && record.flagLabelMange !== '' |
| | | ? Number(record.flagLabelMange) |
| | | : 0, |
| | | locAttrs: normalizeText(record.locAttrs || ''), |
| | | status: record.status !== undefined && record.status !== null ? Number(record.status) : 1, |
| | | memo: normalizeText(record.memo || '') |
| | | } |
| | | } |
| | | |
| | | export function normalizeLocDetailRecord(record = {}) { |
| | | const statusMeta = getLocStatusMeta(record.statusBool ?? record.status) |
| | | const useStatusMeta = getLocUseStatusMeta(record.useStatus) |
| | | const typeIds = normalizeTypeIds(record.typeIds ?? record.type ?? '') |
| | | return { |
| | | ...record, |
| | | warehouseName: normalizeText(record.warehouseId$ || record.warehouseName || ''), |
| | | areaName: normalizeText(record.areaId$ || record.areaName || ''), |
| | | typeIds, |
| | | typeIdsText: normalizeText(record.typeIds$ || record.type$ || record.typeText || record.type || ''), |
| | | code: normalizeText(record.code || ''), |
| | | barcode: normalizeText(record.barcode || ''), |
| | | unit: normalizeText(record.unit || ''), |
| | | fucAtrrs: normalizeText(record.fucAtrrs || ''), |
| | | locAttrs: normalizeText(record.locAttrs || ''), |
| | | memo: normalizeText(record.memo || ''), |
| | | flagLogicText: normalizeFlagText(record.flagLogic), |
| | | flagLabelMangeText: normalizeFlagText(record.flagLabelMange), |
| | | useStatusText: useStatusMeta.text, |
| | | useStatusType: useStatusMeta.type, |
| | | statusText: statusMeta.text, |
| | | statusType: statusMeta.type, |
| | | statusBool: record.statusBool !== void 0 ? Boolean(record.statusBool) : statusMeta.bool, |
| | | row: record.row !== undefined && record.row !== null ? Number(record.row) : void 0, |
| | | col: record.col !== undefined && record.col !== null ? Number(record.col) : void 0, |
| | | lev: record.lev !== undefined && record.lev !== null ? Number(record.lev) : void 0, |
| | | channel: record.channel !== undefined && record.channel !== null ? Number(record.channel) : void 0, |
| | | length: record.length !== undefined && record.length !== null ? Number(record.length) : void 0, |
| | | height: record.height !== undefined && record.height !== null ? Number(record.height) : void 0, |
| | | width: record.width !== undefined && record.width !== null ? Number(record.width) : void 0, |
| | | maxParts: record.maxParts !== undefined && record.maxParts !== null ? Number(record.maxParts) : void 0, |
| | | maxPack: record.maxPack !== undefined && record.maxPack !== null ? Number(record.maxPack) : void 0, |
| | | createByText: normalizeText(record.createBy$ || record.createByText || ''), |
| | | createTimeText: normalizeText(record.createTime$ || record.createTime || ''), |
| | | updateByText: normalizeText(record.updateBy$ || record.updateByText || ''), |
| | | updateTimeText: normalizeText(record.updateTime$ || record.updateTime || '') |
| | | } |
| | | } |
| | | |
| | | export function normalizeLocListRow(record = {}) { |
| | | return normalizeLocDetailRecord(record) |
| | | } |
| | | |
| | | export function buildLocPrintRows(records = []) { |
| | | if (!Array.isArray(records)) { |
| | | return [] |
| | | } |
| | | return records.map((record) => normalizeLocListRow(record)) |
| | | } |
| | | |
| | | export function buildLocReportMeta({ |
| | | previewMeta = {}, |
| | | count = 0, |
| | | orientation = LOC_REPORT_STYLE.orientation |
| | | } = {}) { |
| | | return { |
| | | reportTitle: LOC_REPORT_TITLE, |
| | | reportDate: previewMeta.reportDate, |
| | | printedAt: previewMeta.printedAt, |
| | | operator: previewMeta.operator, |
| | | count, |
| | | reportStyle: { |
| | | ...LOC_REPORT_STYLE, |
| | | orientation |
| | | } |
| | | } |
| | | } |
| | | |
| | | export function resolveLocWarehouseOptions(records = []) { |
| | | if (!Array.isArray(records)) { |
| | | return [] |
| | | } |
| | | |
| | | return records |
| | | .map((item) => { |
| | | if (!item || typeof item !== 'object') { |
| | | return null |
| | | } |
| | | const value = item.id ?? item.value |
| | | if (value === void 0 || value === null || value === '') { |
| | | return null |
| | | } |
| | | return { |
| | | value: Number(value), |
| | | label: normalizeText(item.name || item.code || `仓库 ${value}`) |
| | | } |
| | | }) |
| | | .filter(Boolean) |
| | | } |
| | | |
| | | export function resolveLocAreaOptions(records = []) { |
| | | if (!Array.isArray(records)) { |
| | | return [] |
| | | } |
| | | |
| | | return records |
| | | .map((item) => { |
| | | if (!item || typeof item !== 'object') { |
| | | return null |
| | | } |
| | | const value = item.id ?? item.value |
| | | if (value === void 0 || value === null || value === '') { |
| | | return null |
| | | } |
| | | return { |
| | | value: Number(value), |
| | | label: normalizeText(item.name || item.code || `库区 ${value}`), |
| | | warehouseId: |
| | | item.warehouseId !== undefined && item.warehouseId !== null && item.warehouseId !== '' |
| | | ? Number(item.warehouseId) |
| | | : void 0 |
| | | } |
| | | }) |
| | | .filter(Boolean) |
| | | } |
| | | |
| | | export function resolveLocTypeOptions(records = []) { |
| | | if (!Array.isArray(records)) { |
| | | return [] |
| | | } |
| | | |
| | | return records |
| | | .map((item) => { |
| | | if (!item || typeof item !== 'object') { |
| | | return null |
| | | } |
| | | const value = item.id ?? item.value |
| | | if (value === void 0 || value === null || value === '') { |
| | | return null |
| | | } |
| | | return { |
| | | value: Number(value), |
| | | label: normalizeText(item.name || item.code || item.label || `类型 ${value}`) |
| | | } |
| | | }) |
| | | .filter(Boolean) |
| | | } |
| New file |
| | |
| | | import { h } from 'vue' |
| | | import { ElTag } from 'element-plus' |
| | | import ArtButtonMore from '@/components/core/forms/art-button-more/index.vue' |
| | | import { getLocStatusMeta, getLocUseStatusMeta } from './locPage.helpers' |
| | | |
| | | export function createLocTableColumns({ |
| | | handleView, |
| | | handleEdit, |
| | | handleDelete, |
| | | canEdit = true, |
| | | canDelete = true |
| | | } = {}) { |
| | | const operations = [{ key: 'view', label: '详情', icon: 'ri:eye-line' }] |
| | | |
| | | if (canEdit && handleEdit) { |
| | | operations.push({ key: 'edit', label: '编辑', icon: 'ri:pencil-line' }) |
| | | } |
| | | |
| | | if (canDelete && handleDelete) { |
| | | operations.push({ key: 'delete', label: '删除', icon: 'ri:delete-bin-5-line', color: 'var(--art-error)' }) |
| | | } |
| | | |
| | | return [ |
| | | { type: 'selection', width: 48, align: 'center' }, |
| | | { type: 'globalIndex', label: '序号', width: 72, align: 'center' }, |
| | | { |
| | | prop: 'code', |
| | | label: '库位号', |
| | | minWidth: 160, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.code || '--' |
| | | }, |
| | | { |
| | | prop: 'warehouseName', |
| | | label: '仓库', |
| | | minWidth: 150, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.warehouseName || row.warehouseId$ || '--' |
| | | }, |
| | | { |
| | | prop: 'areaName', |
| | | label: '库区', |
| | | minWidth: 150, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.areaName || row.areaId$ || '--' |
| | | }, |
| | | { |
| | | prop: 'typeIdsText', |
| | | label: '库位类型', |
| | | minWidth: 180, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.typeIdsText || '--' |
| | | }, |
| | | { |
| | | prop: 'row', |
| | | label: '排', |
| | | width: 80, |
| | | align: 'center', |
| | | formatter: (row) => row.row ?? '--' |
| | | }, |
| | | { |
| | | prop: 'col', |
| | | label: '列', |
| | | width: 80, |
| | | align: 'center', |
| | | formatter: (row) => row.col ?? '--' |
| | | }, |
| | | { |
| | | prop: 'lev', |
| | | label: '层', |
| | | width: 80, |
| | | align: 'center', |
| | | formatter: (row) => row.lev ?? '--' |
| | | }, |
| | | { |
| | | prop: 'channel', |
| | | label: '巷道', |
| | | width: 90, |
| | | align: 'center', |
| | | formatter: (row) => row.channel ?? '--' |
| | | }, |
| | | { |
| | | prop: 'useStatus', |
| | | label: '使用状态', |
| | | width: 110, |
| | | align: 'center', |
| | | formatter: (row) => { |
| | | const statusMeta = getLocUseStatusMeta(row.useStatus) |
| | | return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text) |
| | | } |
| | | }, |
| | | { |
| | | prop: 'flagLogicText', |
| | | label: '虚拟库位', |
| | | width: 110, |
| | | align: 'center', |
| | | formatter: (row) => row.flagLogicText || '--' |
| | | }, |
| | | { |
| | | prop: 'flagLabelMangeText', |
| | | label: '标签管理', |
| | | width: 110, |
| | | align: 'center', |
| | | formatter: (row) => row.flagLabelMangeText || '--' |
| | | }, |
| | | { |
| | | prop: 'barcode', |
| | | label: '容器编码', |
| | | minWidth: 150, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.barcode || '--' |
| | | }, |
| | | { |
| | | prop: 'status', |
| | | label: '状态', |
| | | width: 100, |
| | | align: 'center', |
| | | formatter: (row) => { |
| | | const statusMeta = getLocStatusMeta(row.statusBool ?? row.status) |
| | | return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text) |
| | | } |
| | | }, |
| | | { |
| | | prop: 'updateTimeText', |
| | | label: '更新时间', |
| | | minWidth: 170, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.updateTimeText || row.updateTime$ || '--' |
| | | }, |
| | | { |
| | | prop: 'memo', |
| | | label: '备注', |
| | | minWidth: 180, |
| | | showOverflowTooltip: true, |
| | | formatter: (row) => row.memo || '--' |
| | | }, |
| | | { |
| | | prop: 'operation', |
| | | label: '操作', |
| | | width: 160, |
| | | align: 'right', |
| | | formatter: (row) => |
| | | h(ArtButtonMore, { |
| | | list: operations, |
| | | onClick: (item) => { |
| | | if (item.key === 'view') handleView?.(row) |
| | | if (item.key === 'edit') handleEdit?.(row) |
| | | if (item.key === 'delete') handleDelete?.(row) |
| | | } |
| | | }) |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | <template> |
| | | <ElDrawer |
| | | :model-value="visible" |
| | | title="库位详情" |
| | | size="960px" |
| | | destroy-on-close |
| | | @update:model-value="handleVisibleChange" |
| | | > |
| | | <ElScrollbar class="h-[calc(100vh-180px)] pr-1"> |
| | | <div v-if="loading" class="py-6"> |
| | | <ElSkeleton :rows="14" animated /> |
| | | </div> |
| | | <div v-else class="space-y-4"> |
| | | <ElDescriptions title="基础信息" :column="2" border> |
| | | <ElDescriptionsItem label="仓库">{{ detail.warehouseName || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="库区">{{ detail.areaName || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="库位号">{{ detail.code || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="库位类型">{{ detail.typeIdsText || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="使用状态"> |
| | | <ElTag :type="detail.useStatusType || 'info'" effect="light"> |
| | | {{ detail.useStatusText || '--' }} |
| | | </ElTag> |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem label="状态"> |
| | | <ElTag :type="detail.statusType || 'info'" effect="light"> |
| | | {{ detail.statusText || '--' }} |
| | | </ElTag> |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem label="容器编码">{{ detail.barcode || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="存放单位">{{ detail.unit || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="备注" :span="2">{{ detail.memo || '--' }}</ElDescriptionsItem> |
| | | </ElDescriptions> |
| | | |
| | | <ElDescriptions title="位置信息" :column="2" border> |
| | | <ElDescriptionsItem label="排">{{ detail.row ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="列">{{ detail.col ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="层">{{ detail.lev ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="巷道">{{ detail.channel ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="虚拟库位">{{ detail.flagLogicText || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="标签管理">{{ detail.flagLabelMangeText || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="长">{{ detail.length ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="宽">{{ detail.width ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="高">{{ detail.height ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最大零件数">{{ detail.maxParts ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最大包装数">{{ detail.maxPack ?? '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="功能属性" :span="2">{{ detail.fucAtrrs || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="属性" :span="2">{{ detail.locAttrs || '--' }}</ElDescriptionsItem> |
| | | </ElDescriptions> |
| | | |
| | | <ElDescriptions title="审计信息" :column="2" border> |
| | | <ElDescriptionsItem label="创建人">{{ detail.createByText || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="创建时间">{{ detail.createTimeText || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="更新人">{{ detail.updateByText || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="更新时间">{{ detail.updateTimeText || '--' }}</ElDescriptionsItem> |
| | | </ElDescriptions> |
| | | </div> |
| | | </ElScrollbar> |
| | | </ElDrawer> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed } from 'vue' |
| | | |
| | | const props = defineProps({ |
| | | visible: { type: Boolean, default: false }, |
| | | loading: { type: Boolean, default: false }, |
| | | detail: { type: Object, default: () => ({}) } |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:visible']) |
| | | |
| | | const visible = computed({ |
| | | get: () => props.visible, |
| | | set: (value) => emit('update:visible', value) |
| | | }) |
| | | |
| | | function handleVisibleChange(value) { |
| | | visible.value = value |
| | | } |
| | | </script> |
| New file |
| | |
| | | <template> |
| | | <ElDialog |
| | | :title="dialogTitle" |
| | | :model-value="visible" |
| | | width="980px" |
| | | align-center |
| | | destroy-on-close |
| | | @update:model-value="handleCancel" |
| | | @closed="handleClosed" |
| | | > |
| | | <ArtForm |
| | | ref="formRef" |
| | | v-model="form" |
| | | :items="formItems" |
| | | :rules="rules" |
| | | :span="12" |
| | | :gutter="20" |
| | | label-width="110px" |
| | | :show-reset="false" |
| | | :show-submit="false" |
| | | /> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <ElButton @click="handleCancel">取消</ElButton> |
| | | <ElButton type="primary" @click="handleSubmit">确定</ElButton> |
| | | </span> |
| | | </template> |
| | | </ElDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, nextTick, reactive, ref, watch } from 'vue' |
| | | import ArtForm from '@/components/core/forms/art-form/index.vue' |
| | | import { |
| | | buildLocDialogModel, |
| | | createLocFormState, |
| | | getLocBinaryOptions, |
| | | getLocStatusOptions, |
| | | getLocUseStatusOptions |
| | | } from '../locPage.helpers' |
| | | |
| | | const props = defineProps({ |
| | | visible: { type: Boolean, default: false }, |
| | | dialogType: { type: String, default: 'add' }, |
| | | locData: { type: Object, default: () => ({}) }, |
| | | warehouseOptions: { type: Array, default: () => [] }, |
| | | areaOptions: { type: Array, default: () => [] }, |
| | | locTypeOptions: { type: Array, default: () => [] } |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:visible', 'submit']) |
| | | const formRef = ref() |
| | | const form = reactive(createLocFormState()) |
| | | |
| | | const isEdit = computed(() => props.dialogType === 'edit') |
| | | const dialogTitle = computed(() => (isEdit.value ? '编辑库位' : '新增库位')) |
| | | |
| | | const filteredAreaOptions = computed(() => { |
| | | if (!form.warehouseId) { |
| | | return props.areaOptions |
| | | } |
| | | return (props.areaOptions || []).filter((item) => { |
| | | if (item?.warehouseId === undefined || item?.warehouseId === null) { |
| | | return true |
| | | } |
| | | return Number(item.warehouseId) === Number(form.warehouseId) |
| | | }) |
| | | }) |
| | | |
| | | const rules = computed(() => ({ |
| | | warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }], |
| | | areaId: [{ required: true, message: '请选择库区', trigger: 'change' }], |
| | | code: [{ required: true, message: '请输入库位号', trigger: 'blur' }], |
| | | typeIds: [{ type: 'array', required: true, message: '请选择库位类型', trigger: 'change' }], |
| | | row: [{ required: true, message: '请输入排', trigger: 'change' }], |
| | | col: [{ required: true, message: '请输入列', trigger: 'change' }], |
| | | lev: [{ required: true, message: '请输入层', trigger: 'change' }], |
| | | useStatus: [{ required: true, message: '请选择使用状态', trigger: 'change' }] |
| | | })) |
| | | |
| | | const formItems = computed(() => [ |
| | | { |
| | | label: '仓库', |
| | | key: 'warehouseId', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择仓库', |
| | | clearable: true, |
| | | filterable: true, |
| | | options: props.warehouseOptions |
| | | } |
| | | }, |
| | | { |
| | | label: '库区', |
| | | key: 'areaId', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择库区', |
| | | clearable: true, |
| | | filterable: true, |
| | | options: filteredAreaOptions.value |
| | | } |
| | | }, |
| | | { |
| | | label: '库位号', |
| | | key: 'code', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入库位号', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '库位类型', |
| | | key: 'typeIds', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择库位类型', |
| | | clearable: true, |
| | | multiple: true, |
| | | collapseTags: true, |
| | | filterable: true, |
| | | options: props.locTypeOptions |
| | | } |
| | | }, |
| | | { |
| | | label: '使用状态', |
| | | key: 'useStatus', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择使用状态', |
| | | clearable: true, |
| | | filterable: true, |
| | | options: getLocUseStatusOptions() |
| | | } |
| | | }, |
| | | { |
| | | label: '状态', |
| | | key: 'status', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择状态', |
| | | clearable: true, |
| | | options: getLocStatusOptions() |
| | | } |
| | | }, |
| | | { |
| | | label: '排', |
| | | key: 'row', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入排' |
| | | } |
| | | }, |
| | | { |
| | | label: '列', |
| | | key: 'col', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入列' |
| | | } |
| | | }, |
| | | { |
| | | label: '层', |
| | | key: 'lev', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入层' |
| | | } |
| | | }, |
| | | { |
| | | label: '巷道', |
| | | key: 'channel', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入巷道' |
| | | } |
| | | }, |
| | | { |
| | | label: '容器编码', |
| | | key: 'barcode', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入容器编码', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '存放单位', |
| | | key: 'unit', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入存放单位', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '虚拟库位', |
| | | key: 'flagLogic', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择虚拟库位', |
| | | clearable: true, |
| | | options: getLocBinaryOptions() |
| | | } |
| | | }, |
| | | { |
| | | label: '标签管理', |
| | | key: 'flagLabelMange', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择标签管理', |
| | | clearable: true, |
| | | options: getLocBinaryOptions() |
| | | } |
| | | }, |
| | | { |
| | | label: '长', |
| | | key: 'length', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | step: 0.01, |
| | | precision: 2, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入长' |
| | | } |
| | | }, |
| | | { |
| | | label: '宽', |
| | | key: 'width', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | step: 0.01, |
| | | precision: 2, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入宽' |
| | | } |
| | | }, |
| | | { |
| | | label: '高', |
| | | key: 'height', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | step: 0.01, |
| | | precision: 2, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入高' |
| | | } |
| | | }, |
| | | { |
| | | label: '最大零件数', |
| | | key: 'maxParts', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入最大零件数' |
| | | } |
| | | }, |
| | | { |
| | | label: '最大包装数', |
| | | key: 'maxPack', |
| | | type: 'number', |
| | | props: { |
| | | min: 0, |
| | | controlsPosition: 'right', |
| | | placeholder: '请输入最大包装数' |
| | | } |
| | | }, |
| | | { |
| | | label: '功能属性', |
| | | key: 'fucAtrrs', |
| | | type: 'input', |
| | | span: 24, |
| | | props: { |
| | | placeholder: '请输入功能属性', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '属性', |
| | | key: 'locAttrs', |
| | | type: 'input', |
| | | span: 24, |
| | | props: { |
| | | placeholder: '请输入属性', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '备注', |
| | | key: 'memo', |
| | | type: 'input', |
| | | span: 24, |
| | | props: { |
| | | type: 'textarea', |
| | | rows: 3, |
| | | placeholder: '请输入备注', |
| | | clearable: true |
| | | } |
| | | } |
| | | ]) |
| | | |
| | | const loadFormData = () => { |
| | | Object.assign(form, buildLocDialogModel(props.locData)) |
| | | } |
| | | |
| | | const resetForm = () => { |
| | | Object.assign(form, createLocFormState()) |
| | | formRef.value?.clearValidate?.() |
| | | } |
| | | |
| | | const handleSubmit = async () => { |
| | | if (!formRef.value) return |
| | | try { |
| | | await formRef.value.validate() |
| | | emit('submit', { ...form }) |
| | | } catch { |
| | | return |
| | | } |
| | | } |
| | | |
| | | const handleCancel = () => { |
| | | emit('update:visible', false) |
| | | } |
| | | |
| | | const handleClosed = () => { |
| | | resetForm() |
| | | } |
| | | |
| | | watch( |
| | | () => props.visible, |
| | | (visible) => { |
| | | if (visible) { |
| | | loadFormData() |
| | | nextTick(() => { |
| | | formRef.value?.clearValidate?.() |
| | | }) |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ) |
| | | |
| | | watch( |
| | | () => props.locData, |
| | | () => { |
| | | if (props.visible) { |
| | | loadFormData() |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | |
| | | watch( |
| | | () => form.warehouseId, |
| | | () => { |
| | | if (!form.areaId) { |
| | | return |
| | | } |
| | | const available = filteredAreaOptions.value.some((item) => Number(item.value) === Number(form.areaId)) |
| | | if (!available) { |
| | | form.areaId = void 0 |
| | | } |
| | | } |
| | | ) |
| | | </script> |
| New file |
| | |
| | | import assert from 'node:assert/strict' |
| | | import { readFileSync } from 'node:fs' |
| | | import test from 'node:test' |
| | | |
| | | const pageModuleUrl = new URL('../src/views/basic-info/loc/index.vue', import.meta.url) |
| | | const helpersModuleUrl = new URL('../src/views/basic-info/loc/locPage.helpers.js', import.meta.url) |
| | | const columnsModuleUrl = new URL('../src/views/basic-info/loc/locTable.columns.js', import.meta.url) |
| | | const apiModuleUrl = new URL('../src/api/loc.js', import.meta.url) |
| | | const backendMenuAdapterUrl = new URL('../src/router/adapters/backendMenuAdapter.js', import.meta.url) |
| | | const staticRoutesUrl = new URL('../src/router/routes/staticRoutes.js', import.meta.url) |
| | | |
| | | test('loc api exposes the dedicated basic-info backend contract', async () => { |
| | | const apiSource = readFileSync(apiModuleUrl, 'utf8') |
| | | |
| | | assert.match(apiSource, /fetchLocPage/) |
| | | assert.match(apiSource, /fetchGetLocDetail/) |
| | | assert.match(apiSource, /fetchGetLocMany/) |
| | | assert.match(apiSource, /fetchSaveLoc/) |
| | | assert.match(apiSource, /fetchUpdateLoc/) |
| | | assert.match(apiSource, /fetchDeleteLoc/) |
| | | assert.match(apiSource, /fetchLocQuery/) |
| | | assert.match(apiSource, /fetchLocTypeList/) |
| | | assert.match(apiSource, /fetchWarehouseList/) |
| | | assert.match(apiSource, /fetchWarehouseAreasList/) |
| | | assert.match(apiSource, /fetchExportLocReport/) |
| | | assert.match(apiSource, /url:\s*'\/loc\/page'/) |
| | | assert.match(apiSource, /url:\s*'\/loc\/save'/) |
| | | assert.match(apiSource, /url:\s*'\/loc\/update'/) |
| | | assert.match(apiSource, /url:\s*`\/loc\/remove\/\$\{normalizeIds\(ids\)\}`/) |
| | | assert.match(apiSource, /url:\s*'\/locType\/list'/) |
| | | }) |
| | | |
| | | test('loc helpers keep page, save and detail contracts stable', async () => { |
| | | const helpers = await import(helpersModuleUrl) |
| | | |
| | | assert.deepEqual(helpers.createLocSearchState(), { |
| | | condition: '', |
| | | warehouseId: '', |
| | | areaId: '', |
| | | code: '', |
| | | useStatus: '', |
| | | row: '', |
| | | col: '', |
| | | lev: '', |
| | | channel: '', |
| | | status: '', |
| | | barcode: '', |
| | | memo: '' |
| | | }) |
| | | |
| | | assert.deepEqual(helpers.getLocPaginationKey(), { |
| | | current: 'current', |
| | | size: 'pageSize' |
| | | }) |
| | | |
| | | assert.deepEqual( |
| | | helpers.buildLocPageQueryParams({ |
| | | current: 2, |
| | | pageSize: 30, |
| | | condition: ' A区 ', |
| | | warehouseId: '8', |
| | | areaId: '9', |
| | | code: ' LOC-01 ', |
| | | useStatus: ' O ', |
| | | row: '1', |
| | | col: '2', |
| | | lev: '3', |
| | | channel: '4', |
| | | status: '1', |
| | | barcode: ' BOX-01 ', |
| | | memo: ' memo ' |
| | | }), |
| | | { |
| | | current: 2, |
| | | pageSize: 30, |
| | | condition: 'A区', |
| | | warehouseId: 8, |
| | | areaId: 9, |
| | | code: 'LOC-01', |
| | | useStatus: 'O', |
| | | row: 1, |
| | | col: 2, |
| | | lev: 3, |
| | | channel: 4, |
| | | status: 1, |
| | | barcode: 'BOX-01', |
| | | memo: 'memo' |
| | | } |
| | | ) |
| | | |
| | | assert.deepEqual( |
| | | helpers.buildLocSavePayload({ |
| | | id: '8', |
| | | version: '3', |
| | | warehouseId: '5', |
| | | areaId: '6', |
| | | code: ' LOC-01 ', |
| | | typeIds: ['1', '2'], |
| | | flagLogic: 1, |
| | | fucAtrrs: ' 功能 ', |
| | | barcode: ' BOX-01 ', |
| | | unit: ' 箱 ', |
| | | length: '1.2', |
| | | height: '2.3', |
| | | width: '3.4', |
| | | row: '1', |
| | | col: '2', |
| | | lev: '3', |
| | | channel: '4', |
| | | maxParts: '10', |
| | | maxPack: '20', |
| | | useStatus: 'F', |
| | | flagLabelMange: 0, |
| | | locAttrs: ' 属性 ', |
| | | status: '', |
| | | memo: ' 备注 ' |
| | | }), |
| | | { |
| | | id: 8, |
| | | version: 3, |
| | | warehouseId: 5, |
| | | areaId: 6, |
| | | code: 'LOC-01', |
| | | typeIds: [1, 2], |
| | | flagLogic: 1, |
| | | fucAtrrs: '功能', |
| | | barcode: 'BOX-01', |
| | | unit: '箱', |
| | | length: 1.2, |
| | | height: 2.3, |
| | | width: 3.4, |
| | | row: 1, |
| | | col: 2, |
| | | lev: 3, |
| | | channel: 4, |
| | | maxParts: 10, |
| | | maxPack: 20, |
| | | useStatus: 'F', |
| | | flagLabelMange: 0, |
| | | locAttrs: '属性', |
| | | status: 1, |
| | | memo: '备注' |
| | | } |
| | | ) |
| | | |
| | | const detail = helpers.normalizeLocDetailRecord({ |
| | | id: 1, |
| | | warehouseId: 4, |
| | | warehouseId$: '主仓', |
| | | areaId: 8, |
| | | areaId$: 'A区', |
| | | type: '1,2', |
| | | typeIds$: '高库位,中库位', |
| | | useStatus: 'O', |
| | | status: 1, |
| | | flagLogic: 1, |
| | | flagLabelMange: 0, |
| | | code: ' LOC-01 ', |
| | | barcode: ' BOX-01 ', |
| | | unit: ' 箱 ', |
| | | row: 1, |
| | | col: 2, |
| | | lev: 3, |
| | | channel: 4, |
| | | length: 1.2, |
| | | height: 2.3, |
| | | width: 3.4, |
| | | maxParts: 10, |
| | | maxPack: 20, |
| | | memo: ' memo ', |
| | | createBy$: 'ROOT', |
| | | updateBy$: 'ROOT', |
| | | createTime$: '2026-03-30 10:00:00', |
| | | updateTime$: '2026-03-30 10:10:00' |
| | | }) |
| | | |
| | | assert.equal(detail.warehouseName, '主仓') |
| | | assert.equal(detail.areaName, 'A区') |
| | | assert.equal(detail.typeIdsText, '高库位,中库位') |
| | | assert.equal(detail.useStatusText, '空库') |
| | | assert.equal(detail.statusText, '正常') |
| | | assert.equal(detail.flagLogicText, '是') |
| | | assert.equal(detail.flagLabelMangeText, '否') |
| | | assert.equal(detail.memo, 'memo') |
| | | |
| | | assert.deepEqual(helpers.buildLocPrintRows([{ id: 2, code: 'LOC-02', useStatus: 'F', status: 0 }]), [ |
| | | { |
| | | id: 2, |
| | | code: 'LOC-02', |
| | | useStatus: 'F', |
| | | status: 0, |
| | | warehouseName: '', |
| | | areaName: '', |
| | | typeIds: [], |
| | | typeIdsText: '', |
| | | barcode: '', |
| | | unit: '', |
| | | fucAtrrs: '', |
| | | locAttrs: '', |
| | | memo: '', |
| | | flagLogicText: '--', |
| | | flagLabelMangeText: '--', |
| | | useStatusText: '在库', |
| | | useStatusType: 'primary', |
| | | statusText: '冻结', |
| | | statusType: 'danger', |
| | | statusBool: false, |
| | | row: void 0, |
| | | col: void 0, |
| | | lev: void 0, |
| | | channel: void 0, |
| | | length: void 0, |
| | | height: void 0, |
| | | width: void 0, |
| | | maxParts: void 0, |
| | | maxPack: void 0, |
| | | createByText: '', |
| | | createTimeText: '', |
| | | updateByText: '', |
| | | updateTimeText: '' |
| | | } |
| | | ]) |
| | | |
| | | assert.deepEqual(helpers.buildLocReportMeta({ count: 12 }), { |
| | | reportTitle: '库位报表', |
| | | reportDate: undefined, |
| | | printedAt: undefined, |
| | | operator: undefined, |
| | | count: 12, |
| | | reportStyle: { |
| | | titleAlign: 'center', |
| | | titleLevel: 'strong', |
| | | orientation: 'portrait', |
| | | density: 'compact', |
| | | showSequence: true |
| | | } |
| | | }) |
| | | }) |
| | | |
| | | test('loc page skeleton uses ArtDesignPro list page structure', async () => { |
| | | const pageSource = readFileSync(pageModuleUrl, 'utf8') |
| | | const columnsSource = readFileSync(columnsModuleUrl, 'utf8') |
| | | |
| | | assert.match(pageSource, /ArtSearchBar/) |
| | | assert.match(pageSource, /ArtTableHeader/) |
| | | assert.match(pageSource, /ListExportPrint/) |
| | | assert.match(pageSource, /LocDialog/) |
| | | assert.match(pageSource, /LocDetailDrawer/) |
| | | assert.match(pageSource, /useCrudPage/) |
| | | assert.match(pageSource, /usePrintExportPage/) |
| | | assert.match(columnsSource, /label:\s*'库位号'/) |
| | | assert.match(columnsSource, /label:\s*'仓库'/) |
| | | assert.match(columnsSource, /label:\s*'库区'/) |
| | | assert.match(columnsSource, /label:\s*'库位类型'/) |
| | | assert.match(columnsSource, /label:\s*'使用状态'/) |
| | | }) |
| | | |
| | | test('backend menu adapter and static routes expose the loc page', async () => { |
| | | const backendMenuAdapterSource = readFileSync(backendMenuAdapterUrl, 'utf8') |
| | | const staticRoutesSource = readFileSync(staticRoutesUrl, 'utf8') |
| | | |
| | | assert.match(backendMenuAdapterSource, /loc:\s*'\/basic-info\/loc'/) |
| | | assert.match(staticRoutesSource, /path:\s*'loc'/) |
| | | assert.match(staticRoutesSource, /title:\s*'menu\.loc'/) |
| | | assert.match(staticRoutesSource, /basic-info\/loc\/index\.vue/) |
| | | }) |