| | |
| | | <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="'add'" @click="handleShowDialog('add')" v-ripple> |
| | | {{ t('pages.basicInfo.basStationArea.actions.add') }} |
| | | </ElButton> |
| | | <ElButton |
| | | v-auth="'delete'" |
| | | type="danger" |
| | |
| | | @click="handleBatchDelete" |
| | | v-ripple |
| | | > |
| | | 批量删除 |
| | | {{ t('common.actions.batchDelete') }} |
| | | </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> |
| | |
| | | <script setup> |
| | | import { computed, onMounted, ref } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { useI18n } from 'vue-i18n' |
| | | import ListExportPrint from '@/components/biz/list-export-print/index.vue' |
| | | 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 { useUserStore } from '@/store/modules/user' |
| | | import { defaultResponseAdapter } from '@/utils/table/tableUtils' |
| | | import { guardRequestWithMessage } from '@/utils/sys/requestGuard' |
| | | import { fetchDictDataPage } from '@/api/system-manage' |
| | | import { fetchBasStationPage } from '@/api/bas-station' |
| | | import { fetchBasStationOptionPage } from '@/api/bas-station' |
| | | import { fetchWarehouseAreasList } from '@/api/warehouse-areas' |
| | | import { |
| | | fetchBasStationAreaDetail, |
| | | fetchBasStationAreaMany, |
| | | fetchBasStationAreaPage, |
| | | fetchDeleteBasStationArea, |
| | | fetchExportBasStationAreaReport, |
| | | fetchSaveBasStationArea, |
| | | fetchUpdateBasStationArea |
| | | } from '@/api/bas-station-area' |
| | |
| | | import BasStationAreaDetailDrawer from './modules/bas-station-area-detail-drawer.vue' |
| | | import { createBasStationAreaTableColumns } from './basStationAreaTable.columns' |
| | | import { |
| | | BAS_STATION_AREA_REPORT_STYLE, |
| | | buildBasStationAreaDialogModel, |
| | | buildBasStationAreaPageQueryParams, |
| | | buildBasStationAreaPrintRows, |
| | | buildBasStationAreaReportMeta, |
| | | buildBasStationAreaSavePayload, |
| | | buildBasStationAreaSearchParams, |
| | | createBasStationAreaSearchState, |
| | | getBasStationAreaBinaryOptions, |
| | | getBasStationAreaPaginationKey, |
| | | getBasStationAreaReportTitle, |
| | | getBasStationAreaStatusOptions, |
| | | getBasStationAreaTypeOptions, |
| | | normalizeBasStationAreaDetailRecord, |
| | |
| | | defineOptions({ name: 'BasStationArea' }) |
| | | |
| | | const { hasAuth } = useAuth() |
| | | const userStore = useUserStore() |
| | | const { t } = useI18n() |
| | | |
| | | const searchForm = ref(createBasStationAreaSearchState()) |
| | | const detailDrawerVisible = ref(false) |
| | |
| | | const containerTypeOptions = ref([]) |
| | | const stationOptions = ref([]) |
| | | const useStatusOptions = ref([]) |
| | | const stationOptionsLoaded = ref(false) |
| | | const stationOptionsLoading = ref(null) |
| | | let handleDeleteAction = null |
| | | |
| | | const areaLabelMap = computed( |
| | |
| | | const typeLabelMap = computed( |
| | | () => |
| | | new Map( |
| | | getBasStationAreaTypeOptions() |
| | | getBasStationAreaTypeOptions(t) |
| | | .map((item) => [String(item.value), item.label]) |
| | | .filter(([value, label]) => value && label) |
| | | ) |
| | |
| | | const resolveTypeLabel = (value) => typeLabelMap.value.get(String(value)) || '' |
| | | const resolveStationAliasLabel = (id) => stationLabelMap.value.get(String(id)) || '' |
| | | const resolveUseStatusLabel = (value) => useStatusLabelMap.value.get(String(value)) || '' |
| | | const reportTitle = computed(() => getBasStationAreaReportTitle(t)) |
| | | const reportQueryParams = computed(() => buildBasStationAreaSearchParams(searchForm.value)) |
| | | |
| | | const searchItems = computed(() => [ |
| | | { |
| | | label: '关键字', |
| | | label: t('pages.basicInfo.basStationArea.search.condition'), |
| | | key: 'condition', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入站点区域名称/编号/备注' |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.condition') |
| | | } |
| | | }, |
| | | { |
| | | label: '站点区域名称', |
| | | label: t('pages.basicInfo.basStationArea.search.timeStart'), |
| | | key: 'timeStart', |
| | | type: 'date', |
| | | props: { |
| | | clearable: true, |
| | | type: 'date', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.timeStart') |
| | | } |
| | | }, |
| | | { |
| | | label: t('pages.basicInfo.basStationArea.search.timeEnd'), |
| | | key: 'timeEnd', |
| | | type: 'date', |
| | | props: { |
| | | clearable: true, |
| | | type: 'date', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.timeEnd') |
| | | } |
| | | }, |
| | | { |
| | | label: t('pages.basicInfo.basStationArea.search.stationAreaName'), |
| | | key: 'stationAreaName', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入站点区域名称' |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.stationAreaName') |
| | | } |
| | | }, |
| | | { |
| | | label: '站点区域编号', |
| | | label: t('pages.basicInfo.basStationArea.search.stationAreaId'), |
| | | key: 'stationAreaId', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入站点区域编号' |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.stationAreaId') |
| | | } |
| | | }, |
| | | { |
| | | label: '站点类型', |
| | | label: t('pages.basicInfo.basStationArea.search.type'), |
| | | key: 'type', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | options: getBasStationAreaTypeOptions() |
| | | options: getBasStationAreaTypeOptions(t) |
| | | } |
| | | }, |
| | | { |
| | | label: '所属库区', |
| | | label: t('pages.basicInfo.basStationArea.search.area'), |
| | | key: 'area', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '使用状态', |
| | | label: t('pages.basicInfo.basStationArea.search.useStatus'), |
| | | key: 'useStatus', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '可入', |
| | | label: t('pages.basicInfo.basStationArea.search.inAble'), |
| | | key: 'inAble', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '可出', |
| | | label: t('pages.basicInfo.basStationArea.search.outAble'), |
| | | key: 'outAble', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '是否跨区', |
| | | label: t('pages.basicInfo.basStationArea.search.isCrossZone'), |
| | | key: 'isCrossZone', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '是否WCS', |
| | | label: t('pages.basicInfo.basStationArea.search.crossZoneArea'), |
| | | key: 'crossZoneArea', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.crossZoneArea') |
| | | } |
| | | }, |
| | | { |
| | | label: t('pages.basicInfo.basStationArea.search.isWcs'), |
| | | key: 'isWcs', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '自动调拨', |
| | | label: t('pages.basicInfo.basStationArea.search.wcsData'), |
| | | key: 'wcsData', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.wcsData') |
| | | } |
| | | }, |
| | | { |
| | | label: t('pages.basicInfo.basStationArea.search.containerType'), |
| | | key: 'containerType', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.containerType') |
| | | } |
| | | }, |
| | | { |
| | | label: t('pages.basicInfo.basStationArea.search.autoTransfer'), |
| | | key: 'autoTransfer', |
| | | type: 'select', |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | { |
| | | label: '条码', |
| | | label: t('pages.basicInfo.basStationArea.search.barcode'), |
| | | key: 'barcode', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入条码' |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.barcode') |
| | | } |
| | | }, |
| | | { |
| | | label: '状态', |
| | | label: t('pages.basicInfo.basStationArea.search.stationAlias'), |
| | | key: 'stationAlias', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.stationAlias') |
| | | } |
| | | }, |
| | | { |
| | | label: t('pages.basicInfo.basStationArea.search.status'), |
| | | key: 'status', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | options: getBasStationAreaStatusOptions() |
| | | options: getBasStationAreaStatusOptions(t) |
| | | } |
| | | }, |
| | | { |
| | | label: '备注', |
| | | label: t('pages.basicInfo.basStationArea.search.memo'), |
| | | key: 'memo', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入备注' |
| | | placeholder: t('pages.basicInfo.basStationArea.placeholder.memo') |
| | | } |
| | | } |
| | | ]) |
| | |
| | | detailDrawerVisible.value = true |
| | | detailLoading.value = true |
| | | try { |
| | | const detail = await guardRequestWithMessage(fetchBasStationAreaDetail(row.id), {}, { |
| | | timeoutMessage: '站点区域详情加载超时,已停止等待' |
| | | }) |
| | | const detail = await guardRequestWithMessage( |
| | | fetchBasStationAreaDetail(row.id), |
| | | {}, |
| | | { |
| | | timeoutMessage: t('pages.basicInfo.basStationArea.messages.detailTimeout') |
| | | } |
| | | ) |
| | | detailData.value = normalizeBasStationAreaDetailRecord(detail, { |
| | | t, |
| | | resolveAreaLabel, |
| | | resolveCrossZoneAreaLabel, |
| | | resolveContainerTypeLabel, |
| | |
| | | } catch (error) { |
| | | detailDrawerVisible.value = false |
| | | detailData.value = {} |
| | | ElMessage.error(error?.message || '获取站点区域详情失败') |
| | | ElMessage.error( |
| | | error?.message || t('pages.basicInfo.basStationArea.messages.detailLoadFailed') |
| | | ) |
| | | } finally { |
| | | detailLoading.value = false |
| | | } |
| | | } |
| | | |
| | | async function openEditDialog(row) { |
| | | async function ensureStationOptions() { |
| | | if (stationOptionsLoaded.value) { |
| | | return |
| | | } |
| | | |
| | | if (stationOptionsLoading.value) { |
| | | await stationOptionsLoading.value |
| | | return |
| | | } |
| | | |
| | | stationOptionsLoading.value = (async () => { |
| | | const response = await guardRequestWithMessage( |
| | | fetchBasStationOptionPage( |
| | | { |
| | | current: 1, |
| | | pageSize: 100 |
| | | }, |
| | | { |
| | | showErrorMessage: false |
| | | } |
| | | ), |
| | | { records: [] }, |
| | | { |
| | | timeoutMessage: t('pages.basicInfo.basStationArea.messages.stationAliasTimeout') |
| | | } |
| | | ) |
| | | stationOptions.value = resolveBasStationAreaStationOptions( |
| | | defaultResponseAdapter(response).records |
| | | ) |
| | | stationOptionsLoaded.value = true |
| | | })() |
| | | |
| | | try { |
| | | const detail = await guardRequestWithMessage(fetchBasStationAreaDetail(row.id), {}, { |
| | | timeoutMessage: '站点区域详情加载超时,已停止等待' |
| | | }) |
| | | showDialog('edit', detail) |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || '获取站点区域详情失败') |
| | | await stationOptionsLoading.value |
| | | } finally { |
| | | stationOptionsLoading.value = null |
| | | } |
| | | } |
| | | |
| | | const { columns, columnChecks, data, loading, pagination, getData, replaceSearchParams, resetSearchParams, handleSizeChange, handleCurrentChange, refreshData, refreshCreate, refreshUpdate, refreshRemove } = |
| | | useTable({ |
| | | core: { |
| | | apiFn: fetchBasStationAreaPage, |
| | | apiParams: buildBasStationAreaPageQueryParams(searchForm.value), |
| | | paginationKey: getBasStationAreaPaginationKey(), |
| | | columnsFactory: () => |
| | | createBasStationAreaTableColumns({ |
| | | 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) => |
| | | normalizeBasStationAreaListRow(item, { |
| | | resolveAreaLabel, |
| | | resolveCrossZoneAreaLabel, |
| | | resolveContainerTypeLabel, |
| | | resolveTypeLabel, |
| | | resolveStationAliasLabel, |
| | | resolveUseStatusLabel |
| | | }) |
| | | ) |
| | | async function handleShowDialog(type, record) { |
| | | await ensureStationOptions() |
| | | showDialog(type, record) |
| | | } |
| | | |
| | | async function openEditDialog(row) { |
| | | try { |
| | | const detail = await guardRequestWithMessage( |
| | | fetchBasStationAreaDetail(row.id), |
| | | {}, |
| | | { |
| | | timeoutMessage: t('pages.basicInfo.basStationArea.messages.detailTimeout') |
| | | } |
| | | ) |
| | | await handleShowDialog('edit', detail) |
| | | } catch (error) { |
| | | ElMessage.error( |
| | | error?.message || t('pages.basicInfo.basStationArea.messages.detailLoadFailed') |
| | | ) |
| | | } |
| | | } |
| | | |
| | | const { |
| | | columns, |
| | | columnChecks, |
| | | data, |
| | | loading, |
| | | pagination, |
| | | getData, |
| | | replaceSearchParams, |
| | | resetSearchParams, |
| | | handleSizeChange, |
| | | handleCurrentChange, |
| | | refreshData, |
| | | refreshCreate, |
| | | refreshUpdate, |
| | | refreshRemove |
| | | } = useTable({ |
| | | core: { |
| | | apiFn: fetchBasStationAreaPage, |
| | | apiParams: buildBasStationAreaPageQueryParams(searchForm.value), |
| | | paginationKey: getBasStationAreaPaginationKey(), |
| | | columnsFactory: () => |
| | | createBasStationAreaTableColumns({ |
| | | t, |
| | | 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) => |
| | | normalizeBasStationAreaListRow(item, { |
| | | t, |
| | | resolveAreaLabel, |
| | | resolveCrossZoneAreaLabel, |
| | | resolveContainerTypeLabel, |
| | | resolveTypeLabel, |
| | | resolveStationAliasLabel, |
| | | resolveUseStatusLabel |
| | | }) |
| | | ) |
| | | } |
| | | }) |
| | | } |
| | | }) |
| | | |
| | | const { |
| | | dialogVisible, |
| | |
| | | saveRequest: fetchSaveBasStationArea, |
| | | updateRequest: fetchUpdateBasStationArea, |
| | | deleteRequest: fetchDeleteBasStationArea, |
| | | entityName: '站点区域', |
| | | entityName: t('pages.basicInfo.basStationArea.entity'), |
| | | resolveRecordLabel: (record) => record?.stationAreaName || record?.stationAreaId || record?.id, |
| | | refreshCreate, |
| | | refreshUpdate, |
| | | refreshRemove |
| | | }) |
| | | handleDeleteAction = handleDelete |
| | | |
| | | const buildPreviewMeta = (rows) => { |
| | | const now = new Date() |
| | | return { |
| | | reportDate: now.toLocaleDateString('zh-CN'), |
| | | printedAt: now.toLocaleString('zh-CN', { hour12: false }), |
| | | operator: userStore.getUserInfo?.name || userStore.getUserInfo?.username || '', |
| | | count: rows.length, |
| | | reportStyle: { ...BAS_STATION_AREA_REPORT_STYLE } |
| | | } |
| | | } |
| | | |
| | | const resolvePrintRecords = async (payload) => { |
| | | if (Array.isArray(payload?.ids) && payload.ids.length > 0) { |
| | | return defaultResponseAdapter(await fetchBasStationAreaMany(payload.ids)).records |
| | | } |
| | | return defaultResponseAdapter( |
| | | await fetchBasStationAreaPage({ |
| | | ...reportQueryParams.value, |
| | | current: 1, |
| | | pageSize: |
| | | Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20 |
| | | }) |
| | | ).records |
| | | } |
| | | |
| | | const { |
| | | previewVisible, |
| | | previewRows, |
| | | previewMeta, |
| | | handlePreviewVisibleChange, |
| | | handleExport, |
| | | handlePrint |
| | | } = usePrintExportPage({ |
| | | downloadFileName: 'bas-station-area.xlsx', |
| | | requestExport: (payload) => |
| | | fetchExportBasStationAreaReport(payload, { |
| | | headers: { |
| | | Authorization: userStore.accessToken || '' |
| | | } |
| | | }), |
| | | resolvePrintRecords, |
| | | buildPreviewRows: (records) => |
| | | buildBasStationAreaPrintRows(records, { |
| | | t, |
| | | resolveAreaLabel, |
| | | resolveCrossZoneAreaLabel, |
| | | resolveContainerTypeLabel, |
| | | resolveTypeLabel, |
| | | resolveStationAliasLabel, |
| | | resolveUseStatusLabel |
| | | }), |
| | | buildPreviewMeta |
| | | }) |
| | | |
| | | const resolvedPreviewMeta = computed(() => |
| | | buildBasStationAreaReportMeta({ |
| | | previewMeta: previewMeta.value, |
| | | count: previewRows.value.length, |
| | | orientation: |
| | | previewMeta.value?.reportStyle?.orientation || BAS_STATION_AREA_REPORT_STYLE.orientation, |
| | | t |
| | | }) |
| | | ) |
| | | |
| | | function handleSearch(params) { |
| | | replaceSearchParams(buildBasStationAreaSearchParams(params)) |
| | |
| | | |
| | | async function loadAreaOptions() { |
| | | const response = await guardRequestWithMessage(fetchWarehouseAreasList(), [], { |
| | | timeoutMessage: '库区选项加载超时,已停止等待' |
| | | timeoutMessage: t('pages.basicInfo.basStationArea.messages.areaOptionsTimeout') |
| | | }) |
| | | const options = resolveBasStationAreaWarehouseAreaOptions(defaultResponseAdapter(response).records) |
| | | const options = resolveBasStationAreaWarehouseAreaOptions( |
| | | defaultResponseAdapter(response).records |
| | | ) |
| | | areaOptions.value = options |
| | | crossZoneAreaOptions.value = options |
| | | } |
| | | |
| | | async function loadStationOptions() { |
| | | const response = await guardRequestWithMessage( |
| | | fetchBasStationPage({ |
| | | current: 1, |
| | | pageSize: 500 |
| | | }, { |
| | | showErrorMessage: false |
| | | }), |
| | | { records: [] }, |
| | | { |
| | | timeoutMessage: '站点别名选项加载超时,已停止等待' |
| | | } |
| | | ) |
| | | stationOptions.value = resolveBasStationAreaStationOptions(defaultResponseAdapter(response).records) |
| | | } |
| | | |
| | | async function loadContainerTypeOptions() { |
| | |
| | | status: 1 |
| | | }), |
| | | { records: [] }, |
| | | { timeoutMessage: '容器类型选项加载超时,已停止等待' } |
| | | { timeoutMessage: t('pages.basicInfo.basStationArea.messages.containerTypeTimeout') } |
| | | ) |
| | | containerTypeOptions.value = resolveBasStationAreaContainerTypeOptions(defaultResponseAdapter(response).records) |
| | | containerTypeOptions.value = resolveBasStationAreaContainerTypeOptions( |
| | | defaultResponseAdapter(response).records |
| | | ) |
| | | } |
| | | |
| | | async function loadUseStatusOptions() { |
| | |
| | | status: 1 |
| | | }), |
| | | { records: [] }, |
| | | { timeoutMessage: '使用状态选项加载超时,已停止等待' } |
| | | { timeoutMessage: t('pages.basicInfo.basStationArea.messages.useStatusTimeout') } |
| | | ) |
| | | useStatusOptions.value = resolveBasStationAreaUseStatusOptions(defaultResponseAdapter(response).records) |
| | | useStatusOptions.value = resolveBasStationAreaUseStatusOptions( |
| | | defaultResponseAdapter(response).records |
| | | ) |
| | | } |
| | | |
| | | onMounted(async () => { |
| | | await Promise.allSettled([ |
| | | loadAreaOptions(), |
| | | loadStationOptions(), |
| | | loadContainerTypeOptions(), |
| | | loadUseStatusOptions() |
| | | ]) |