feat(pl): add Excel export for plan and transport lists
Support filtered/selected export on plan, archive, cert and transport pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
b06fb6ac56
commit
6a89452f1a
7 files changed
+339
-5
No files matched your search
@@ -138,9 +138,9 @@ export interface VehicleQuery {
|
||||
|
||||
export const vehicleApi = {
|
||||
list: (params?: VehicleQuery) =>
|
||||
request.get<PlListResponse<Vehicle>>('/transport/vehicle', { params }),
|
||||
export: (data: Record<string, any>) =>
|
||||
request.post('/transport/vehicle/export', data, { responseType: 'blob' }),
|
||||
request.get<PlListResponse<Vehicle>>('/transport/vehicle', { params }),
|
||||
get: (id: string) => request.get<VehicleDetail>(`/transport/vehicle/${id}`),
|
||||
create: (data: VehiclePayload) => request.post<VehicleDetail>('/transport/vehicle', data),
|
||||
update: (id: string, data: Partial<VehiclePayload>) =>
|
||||
@@ -194,9 +194,9 @@ export interface PersonnelQuery {
|
||||
|
||||
export const personnelApi = {
|
||||
list: (params?: PersonnelQuery) =>
|
||||
request.get<PlListResponse<Personnel>>('/transport/personnel', { params }),
|
||||
export: (data: Record<string, any>) =>
|
||||
request.post('/transport/personnel/export', data, { responseType: 'blob' }),
|
||||
request.get<PlListResponse<Personnel>>('/transport/personnel', { params }),
|
||||
get: (id: string) => request.get<PersonnelDetail>(`/transport/personnel/${id}`),
|
||||
create: (data: PersonnelPayload) => request.post<PersonnelDetail>('/transport/personnel', data),
|
||||
update: (id: string, data: Partial<PersonnelPayload>) =>
|
||||
@@ -696,6 +696,8 @@ export interface PlanContractGapQuery {
|
||||
|
||||
export const planApi = {
|
||||
list: (params?: PlanQuery) => request.get<PlanListResponse>('/transport/plan/', { params }),
|
||||
export: (data: Record<string, any>) =>
|
||||
request.post('/transport/plan/export', data, { responseType: 'blob' }),
|
||||
get: (id: string) => request.get<Plan>(`/transport/plan/${id}`),
|
||||
countByContract: (contractIds: string[]) =>
|
||||
request.get<{ counts: Record<string, number> }>('/transport/plan/count-by-contract', {
|
||||
@@ -1002,6 +1004,8 @@ export interface TransportListResponse {
|
||||
|
||||
export const transportApi = {
|
||||
list: (params?: TransportQuery) => request.get<TransportListResponse>('/transport/order/', { params }),
|
||||
export: (data: Record<string, any>) =>
|
||||
request.post('/transport/order/export', data, { responseType: 'blob' }),
|
||||
get: (id: string) => request.get<Transport>(`/transport/order/${id}`),
|
||||
create: (data: Partial<Transport> & { planIds?: string[] }) =>
|
||||
request.post<Transport>('/transport/order/', data),
|
||||
|
||||
@@ -95,6 +95,15 @@
|
||||
<el-icon><FolderChecked /></el-icon>
|
||||
{{ selectedPlan ? archiveButtonLabel(selectedPlan) : '归档' }}
|
||||
</el-button>
|
||||
<ListExportDropdown
|
||||
:export-fn="planApi.export"
|
||||
:get-filter-params="getPlanArchiveExportFilterParams"
|
||||
:has-selection="true"
|
||||
:selected-ids="selectedRows.map((r) => r.id)"
|
||||
:visible-columns="planArchiveExportColumns"
|
||||
filename="计划归档.xlsx"
|
||||
/>
|
||||
|
||||
<ListToolbarEndActions
|
||||
:loading="loading"
|
||||
:column-defs="listColumnDefs"
|
||||
@@ -351,6 +360,7 @@
|
||||
<script setup lang="ts">
|
||||
import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
|
||||
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
|
||||
import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
|
||||
import ListColumnStatsRow from '@/components/business/list-column-stats-row/index.vue'
|
||||
import type { StatsRowColumn } from '@/utils/list-column-stats'
|
||||
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
|
||||
@@ -478,6 +488,28 @@ function getArchiveStatCellValue(row: Plan, prop: string): unknown {
|
||||
}
|
||||
|
||||
const selectedRows = ref<Plan[]>([])
|
||||
function getPlanArchiveExportFilterParams() {
|
||||
const keyword = quickSearch.value.trim()
|
||||
return {
|
||||
q: keyword || undefined,
|
||||
planNo: keyword ? undefined : searchForm.planNo || undefined,
|
||||
planType: searchForm.planType || undefined,
|
||||
followStatus: searchForm.followStatus || undefined,
|
||||
transportStatus: 'arranged',
|
||||
customerName: keyword ? undefined : searchForm.customerName || undefined,
|
||||
productName: keyword ? undefined : searchForm.productName || undefined,
|
||||
archiveStatus: searchForm.archiveStatus || undefined,
|
||||
planDateFrom: dateRange.value?.[0] || undefined,
|
||||
planDateTo: dateRange.value?.[1] || undefined
|
||||
}
|
||||
}
|
||||
|
||||
const planArchiveExportColumns = computed(() => {
|
||||
const cols = [...visibleColumns.value]
|
||||
if (!cols.includes('planNo')) cols.unshift('planNo')
|
||||
return cols
|
||||
})
|
||||
|
||||
const viewingPlan = ref<Plan | null>(null)
|
||||
|
||||
function syncViewingPlanFromList() {
|
||||
|
||||
@@ -135,6 +135,15 @@
|
||||
<el-icon><CircleClose /></el-icon>取消齐备
|
||||
</el-button>
|
||||
|
||||
<ListExportDropdown
|
||||
:export-fn="planApi.export"
|
||||
:get-filter-params="getPlanCertExportFilterParams"
|
||||
:has-selection="true"
|
||||
:selected-ids="selectedRows.map((r) => r.id)"
|
||||
:visible-columns="planCertExportColumns"
|
||||
filename="计划证件.xlsx"
|
||||
/>
|
||||
|
||||
<ListToolbarEndActions
|
||||
:loading="loading"
|
||||
:column-defs="listColumnDefs"
|
||||
@@ -413,6 +422,7 @@ import PlPlanListCertCell from '@/components/business/pl-plan-list-cert-cell/ind
|
||||
import PlPlanListProductCell from '@/components/business/pl-plan-list-product-cell/index.vue'
|
||||
import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
|
||||
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
|
||||
import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
|
||||
import {
|
||||
buildHazardCertReadyConfirmMessage,
|
||||
isHazardCertReady,
|
||||
@@ -477,6 +487,27 @@ const {
|
||||
} = usePersistedListColumns('pl-plan-cert-list-columns', listColumnDefs)
|
||||
|
||||
const selectedRows = ref<Plan[]>([])
|
||||
function getPlanCertExportFilterParams() {
|
||||
const keyword = quickSearch.value.trim()
|
||||
return {
|
||||
q: keyword || undefined,
|
||||
planNo: keyword ? undefined : searchForm.planNo || undefined,
|
||||
planType: searchForm.planType || undefined,
|
||||
followStatus: searchForm.followStatus || undefined,
|
||||
customerName: keyword ? undefined : searchForm.customerName || undefined,
|
||||
planDateFrom: dateRange.value?.[0] || undefined,
|
||||
planDateTo: dateRange.value?.[1] || undefined,
|
||||
hasHazardProduct: 1,
|
||||
certUploadStatus: searchForm.certUploadStatus || undefined
|
||||
}
|
||||
}
|
||||
|
||||
const planCertExportColumns = computed(() => {
|
||||
const cols = [...visibleColumns.value]
|
||||
if (!cols.includes('planNo')) cols.unshift('planNo')
|
||||
return cols
|
||||
})
|
||||
|
||||
const viewingPlan = ref<Plan | null>(null)
|
||||
const selectedPlan = computed(() => (selectedRows.value.length === 1 ? selectedRows.value[0] : null))
|
||||
const dateRange = ref<string[]>([])
|
||||
|
||||
@@ -183,6 +183,15 @@
|
||||
<el-icon><EditPen /></el-icon>强制改状态
|
||||
</el-button>
|
||||
|
||||
<ListExportDropdown
|
||||
:export-fn="planApi.export"
|
||||
:get-filter-params="getPlanExportFilterParams"
|
||||
:has-selection="true"
|
||||
:selected-ids="selectedRows.map((r) => r.id)"
|
||||
:visible-columns="planExportColumns"
|
||||
filename="计划列表.xlsx"
|
||||
/>
|
||||
|
||||
<ListToolbarEndActions
|
||||
:loading="loading"
|
||||
:column-defs="listColumnDefs"
|
||||
@@ -626,6 +635,7 @@ import PlPasteRecognizeDialog from '@/components/business/pl-paste-recognize-dia
|
||||
import PlPlanFormDialog from '@/components/business/pl-plan-form-dialog/index.vue'
|
||||
import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
|
||||
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
|
||||
import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
|
||||
import ListColumnStatsRow from '@/components/business/list-column-stats-row/index.vue'
|
||||
import type { StatsRowColumn } from '@/utils/list-column-stats'
|
||||
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
|
||||
@@ -761,6 +771,27 @@ function getPlanStatCellValue(row: Plan, prop: string): unknown {
|
||||
}
|
||||
|
||||
const selectedRows = ref<Plan[]>([])
|
||||
function getPlanExportFilterParams() {
|
||||
const keyword = quickSearch.value.trim()
|
||||
return {
|
||||
q: keyword || undefined,
|
||||
planNo: keyword ? undefined : searchForm.planNo || undefined,
|
||||
planType: tabFilters.planType || undefined,
|
||||
followStatus: tabFilters.followStatus || searchForm.followStatus || undefined,
|
||||
customerName: keyword ? undefined : searchForm.customerName || undefined,
|
||||
productName: keyword ? undefined : searchForm.productName || undefined,
|
||||
licensePlate: keyword ? undefined : searchForm.licensePlate || undefined,
|
||||
planDateFrom: dateRange.value?.[0] || undefined,
|
||||
planDateTo: dateRange.value?.[1] || undefined
|
||||
}
|
||||
}
|
||||
|
||||
const planExportColumns = computed(() => {
|
||||
const cols = [...visibleColumns.value]
|
||||
if (!cols.includes('planNo')) cols.unshift('planNo')
|
||||
return cols
|
||||
})
|
||||
|
||||
const viewingPlan = ref<Plan | null>(null)
|
||||
|
||||
function syncViewingPlanFromList() {
|
||||
|
||||
@@ -62,6 +62,15 @@
|
||||
<el-icon><Share /></el-icon>二维码
|
||||
</el-button>
|
||||
|
||||
<ListExportDropdown
|
||||
:export-fn="transportApi.export"
|
||||
:get-filter-params="getTransportExportFilterParams"
|
||||
:has-selection="true"
|
||||
:selected-ids="selectedRows.map((r) => r.id)"
|
||||
:visible-columns="transportExportColumns"
|
||||
filename="运输列表.xlsx"
|
||||
/>
|
||||
|
||||
<ListToolbarEndActions
|
||||
:loading="loading"
|
||||
:column-defs="listColumnDefs"
|
||||
@@ -250,6 +259,7 @@ import SystemViewDialog, {
|
||||
import { transportApi, type Transport } from '@/api/pl'
|
||||
import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
|
||||
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
|
||||
import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
|
||||
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
|
||||
import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
|
||||
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
|
||||
@@ -283,6 +293,22 @@ const detailLoading = ref(false)
|
||||
const qrcodeLoading = ref(false)
|
||||
const transportList = ref<Transport[]>([])
|
||||
const selectedRows = ref<Transport[]>([])
|
||||
function getTransportExportFilterParams() {
|
||||
const keyword = quickSearchKeyword.value.trim()
|
||||
return {
|
||||
q: keyword || undefined,
|
||||
transportNo: keyword ? undefined : searchForm.transportNo || undefined,
|
||||
transportStatus: searchForm.transportStatus || undefined,
|
||||
approvalStatus: searchForm.approvalStatus || undefined
|
||||
}
|
||||
}
|
||||
|
||||
const transportExportColumns = computed(() => {
|
||||
const cols = [...visibleColumns.value]
|
||||
if (!cols.includes('transportNo')) cols.unshift('transportNo')
|
||||
return cols
|
||||
})
|
||||
|
||||
const detailVisible = ref(false)
|
||||
const currentTransport = ref<Transport | null>(null)
|
||||
|
||||
|
||||
Reference in new issue
Block a user