feat: add column sorting and advanced filtering for purchase inbound

Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
dxc
2026-03-02 15:39:32 +08:00
parent 2ac64076dd
commit 893be24071
3 changed files with 234 additions and 8 deletions

View File

@ -53,6 +53,33 @@
<el-button type="primary" plain class="search-btn" @click="fetchData">搜索</el-button>
<el-button class="reset-btn" @click="resetQuery">重置</el-button>
<el-popover
v-model:visible="advancedFilterVisible"
placement="bottom"
title="高级筛选"
width="600"
trigger="manual">
<template #reference>
<el-button plain @click="advancedFilterVisible = !advancedFilterVisible">高级筛选</el-button>
</template>
<div class="advanced-filter">
<div v-for="(condition, index) in advancedConditions" :key="index" class="condition-row" style="display: flex; align-items: center; margin-bottom: 10px;">
<el-select v-model="condition.field" placeholder="字段" style="width: 180px">
<el-option v-for="field in fieldOptions" :key="field.value" :label="field.label" :value="field.value" />
</el-select>
<el-select v-model="condition.operator" placeholder="操作符" style="width: 120px; margin-left: 8px">
<el-option v-for="op in operatorOptions" :key="op.value" :label="op.label" :value="op.value" />
</el-select>
<el-input v-model="condition.value" placeholder="值" style="width: 180px; margin-left: 8px" />
<el-button v-if="advancedConditions.length > 1" type="danger" link @click="removeCondition(index)" style="margin-left: 8px">删除</el-button>
</div>
<div style="margin-top: 12px">
<el-button type="primary" link @click="addCondition">添加条件</el-button>
<el-button @click="applyAdvancedFilter" type="primary">应用筛选</el-button>
<el-button @click="resetAdvancedFilter">重置</el-button>
</div>
</div>
</el-popover>
</div>
<div class="right-actions" style="flex-wrap: wrap;">
@ -90,6 +117,7 @@
class="modern-table"
highlight-current-row
header-cell-class-name="table-header-gray"
@sort-change="handleSortChange"
>
<template v-for="col in allColumns" :key="col.prop">
<el-table-column
@ -98,6 +126,7 @@
:label="col.label"
:min-width="col.minWidth || '140'"
show-overflow-tooltip
:sortable="isColumnSortable(col.prop) ? 'custom' : false"
>
<template #default="scope" v-if="col.prop === 'material_name'">
<span class="clickable-text" @click="handleUpdate(scope.row)">
@ -723,7 +752,10 @@ const queryParams = reactive({
category: '',
material_type: '',
company: '',
statuses: ['在库', '借库']
statuses: ['在库', '借库'],
orderByColumn: '',
isAsc: undefined as string | undefined,
advancedFilters: [] as any[]
})
const materialOptions = ref<any[]>([])
@ -750,6 +782,44 @@ const cameraRef = ref<InstanceType<typeof WebRtcCamera> | null>(null)
const currentCameraField = ref<'arrival_photo' | 'inspection_report'>('arrival_photo')
const inspection_report_url = ref('')
const advancedFilterVisible = ref(false)
const advancedConditions = ref([{ field: '', operator: '', value: '' }])
const fieldOptions = ref([
{ value: 'company_name', label: '所属公司' },
{ value: 'material_name', label: '名称' },
{ value: 'material_type', label: '类型' },
{ value: 'category', label: '类别' },
{ value: 'spec_model', label: '规格型号' },
{ value: 'unit', label: '单位' },
{ value: 'sku', label: 'SKU' },
{ value: 'barcode', label: '条码' },
{ value: 'batch_number', label: '批号' },
{ value: 'serial_number', label: '序列号' },
{ value: 'warehouse_location', label: '库位' },
{ value: 'status', label: '状态' },
{ value: 'inspection_status', label: '到检状态' },
{ value: 'qty_inbound', label: '入库量' },
{ value: 'qty_stock', label: '库存数' },
{ value: 'qty_available', label: '可用数' },
{ value: 'unit_price', label: '不含税单价' },
{ value: 'total_price', label: '不含税总价' },
{ value: 'tax_rate', label: '税率' },
{ value: 'currency', label: '币种' },
{ value: 'exchange_rate', label: '汇率' },
{ value: 'supplier_name', label: '供应商' },
{ value: 'purchaser', label: '采购人' },
{ value: 'purchaser_email', label: '采购邮箱' },
{ value: 'source_link', label: '原始链接' },
{ value: 'detail_link', label: '详情链接' },
])
const operatorOptions = ref([
{ value: 'eq', label: '等于' },
{ value: 'ne', label: '不等于' },
{ value: 'contains', label: '包含' },
{ value: 'ge', label: '大于等于' },
{ value: 'le', label: '小于等于' }
])
// 基础列
const baseColumns = [
{prop: 'company_name', label: '所属公司'},
@ -1123,7 +1193,10 @@ const fetchData = async () => {
try {
const params = {
...queryParams,
statuses: queryParams.statuses.join(',')
statuses: queryParams.statuses.join(','),
orderByColumn: queryParams.orderByColumn,
isAsc: queryParams.isAsc,
advancedFilters: JSON.stringify(queryParams.advancedFilters)
}
const res: any = await getBuyList(params)
tableData.value = res.data.items || []
@ -1347,6 +1420,42 @@ const handleCameraConfirm = async (file: File) => {
}
}
const addCondition = () => {
advancedConditions.value.push({ field: '', operator: '', value: '' })
}
const removeCondition = (index: number) => {
advancedConditions.value.splice(index, 1)
}
const applyAdvancedFilter = () => {
const validConditions = advancedConditions.value.filter(c => c.field && c.operator && c.value !== '')
queryParams.advancedFilters = validConditions
advancedFilterVisible.value = false
queryParams.page = 1
fetchData()
}
const resetAdvancedFilter = () => {
advancedConditions.value = [{ field: '', operator: '', value: '' }]
queryParams.advancedFilters = []
advancedFilterVisible.value = false
queryParams.page = 1
fetchData()
}
const isColumnSortable = (prop: string) => {
const sortableColumns = ['company_name', 'material_name', 'material_type', 'category', 'spec_model', 'unit', 'sku', 'barcode', 'inbound_date', 'serial_number', 'batch_number', 'status', 'inspection_status', 'qty_inbound', 'qty_stock', 'qty_available', 'warehouse_loc', 'unit_price', 'total_price', 'tax_rate', 'currency', 'exchange_rate', 'supplier_name', 'purchaser', 'purchaser_email', 'source_link', 'detail_link']
return sortableColumns.includes(prop)
}
const handleSortChange = ({ column, prop, order }: any) => {
if (prop && isColumnSortable(prop)) {
queryParams.orderByColumn = prop
queryParams.isAsc = order === 'ascending' ? 'asc' : order === 'descending' ? 'desc' : undefined
} else {
queryParams.orderByColumn = ''
queryParams.isAsc = undefined
}
queryParams.page = 1
fetchData()
}
const handleDelete = async (row: any) => { try { await deleteBuyInbound(row.id); ElMessage.success('删除成功'); fetchData() } catch (e) { ElMessage.error('删除失败') } }
// ------------------------------------
@ -1602,4 +1711,4 @@ onMounted(() => {
.long-dropdown .el-input__suffix {
z-index: 10;
}
</style>
</style>