feat: add table sorting and advanced filtering for products
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
@ -53,6 +53,36 @@
|
||||
<el-button type="primary" plain class="search-btn" @click="fetchData">搜索</el-button>
|
||||
<el-button class="reset-btn" @click="resetQuery">重置</el-button>
|
||||
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
width="600"
|
||||
trigger="click"
|
||||
v-model:visible="advancedFilterVisible"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="primary" plain>高级筛选</el-button>
|
||||
</template>
|
||||
<div style="padding: 10px;">
|
||||
<div v-for="(cond, idx) in advancedConditions" :key="idx" style="display: flex; gap: 10px; margin-bottom: 10px; align-items: center;">
|
||||
<el-select v-model="cond.field" placeholder="字段" style="width: 150px;">
|
||||
<el-option v-for="opt in fieldOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
<el-select v-model="cond.operator" placeholder="操作符" style="width: 120px;">
|
||||
<el-option v-for="opt in operatorOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
<el-input v-model="cond.value" placeholder="值" style="flex: 1;" />
|
||||
<el-button type="danger" size="small" @click="removeCondition(idx)" :disabled="advancedConditions.length === 1">删除</el-button>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 10px;">
|
||||
<el-button type="primary" size="small" @click="addCondition">添加条件</el-button>
|
||||
<div>
|
||||
<el-button size="small" @click="resetAdvancedFilter">重置</el-button>
|
||||
<el-button type="primary" size="small" @click="applyAdvancedFilter">应用</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.statuses"
|
||||
multiple
|
||||
@ -88,7 +118,9 @@
|
||||
stripe
|
||||
style="width: 100%"
|
||||
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
|
||||
@ -96,6 +128,7 @@
|
||||
:prop="col.prop"
|
||||
:label="col.label"
|
||||
:min-width="col.minWidth || '110'"
|
||||
:sortable="col.sortable ? 'custom' : false"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
|
||||
@ -515,10 +548,52 @@ const dialogStatus = ref<'create' | 'update'>('create')
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const formRef = ref()
|
||||
const queryParams = reactive({ page: 1, pageSize: 100, keyword: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '' })
|
||||
const queryParams = reactive({ page: 1, pageSize: 100, keyword: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '', orderByColumn: '', isAsc: '', advancedFilters: [] })
|
||||
const categoryOptions = ref<string[]>([])
|
||||
const typeOptions = ref<string[]>([])
|
||||
const companyOptions = ref<string[]>([]) // [新增]
|
||||
const advancedFilterVisible = ref(false)
|
||||
const advancedConditions = ref([{ field: '', operator: '', value: '' }])
|
||||
const fieldOptions = ref([
|
||||
{ label: 'ID', value: 'id' },
|
||||
{ label: 'BaseID', value: 'base_id' },
|
||||
{ label: '所属公司', value: 'company_name' },
|
||||
{ label: '名称', value: 'material_name' },
|
||||
{ label: '规格型号', value: 'spec_model' },
|
||||
{ label: '类别', value: 'category' },
|
||||
{ label: '类型', value: 'material_type' },
|
||||
{ label: '单位', value: 'unit' },
|
||||
{ label: 'SKU', value: 'sku' },
|
||||
{ label: '入库日期', value: 'inbound_date' },
|
||||
{ label: '条码', value: 'barcode' },
|
||||
{ label: '序列号', value: 'serial_number' },
|
||||
{ label: '批号', value: 'batch_number' },
|
||||
{ label: '状态', value: 'status' },
|
||||
{ label: '质量状态', value: 'quality_status' },
|
||||
{ label: '入库量', value: 'in_quantity' },
|
||||
{ label: '库存数', value: 'stock_quantity' },
|
||||
{ label: '可用数', value: 'available_quantity' },
|
||||
{ label: '库位', value: 'warehouse_location' },
|
||||
{ label: 'BOM编号', value: 'bom_code' },
|
||||
{ label: 'BOM版本', value: 'bom_version' },
|
||||
{ label: '工单号', value: 'work_order_code' },
|
||||
{ label: '原料成本', value: 'raw_material_cost' },
|
||||
{ label: '单件成本', value: 'unit_total_cost' },
|
||||
{ label: '总成本', value: 'total_price' },
|
||||
{ label: '生产负责人', value: 'production_manager' },
|
||||
{ label: '生产开始', value: 'production_start_time' },
|
||||
{ label: '生产结束', value: 'production_end_time' },
|
||||
])
|
||||
const operatorOptions = ref([
|
||||
{ label: '等于', value: '=' },
|
||||
{ label: '不等于', value: '!=' },
|
||||
{ label: '包含', value: 'like' },
|
||||
{ label: '不包含', value: 'not_like' },
|
||||
{ label: '大于', value: '>' },
|
||||
{ label: '小于', value: '<' },
|
||||
{ label: '大于等于', value: '>=' },
|
||||
{ label: '小于等于', value: '<=' },
|
||||
])
|
||||
const materialOptions = ref<any[]>([])
|
||||
const searchPage = ref(1)
|
||||
const searchKeyword = ref('')
|
||||
@ -551,28 +626,28 @@ const inspection_url = ref('')
|
||||
|
||||
// [核心优化] 所有列定义
|
||||
const allColumns = [
|
||||
{ prop: 'company_name', label: '所属公司', minWidth: '100' }, // [新增]
|
||||
{ prop: 'material_name', label: '名称', minWidth: '140' },
|
||||
{ prop: 'sku', label: 'SKU', minWidth: '110' },
|
||||
{ prop: 'serial_number', label: '序列号', minWidth: '130' },
|
||||
{ prop: 'qty_stock', label: '库存', minWidth: '90' },
|
||||
{ prop: 'status', label: '状态', minWidth: '90' },
|
||||
{ prop: 'quality_status', label: '质量', minWidth: '90' },
|
||||
{ prop: 'spec_model', label: '规格', minWidth: '120' },
|
||||
{ prop: 'unit', label: '单位', minWidth: '80' },
|
||||
{ prop: 'product_photo', label: '实拍图', minWidth: '100' },
|
||||
{ prop: 'sale_price', label: '售价', minWidth: '100' },
|
||||
{ prop: 'order_id', label: '订单号', minWidth: '120' },
|
||||
{ prop: 'work_order_code', label: '工单号', minWidth: '120' },
|
||||
{ prop: 'quality_report_link', label: '质量报告', minWidth: '100' },
|
||||
{ prop: 'inspection_report_link', label: '检测报告', minWidth: '100' },
|
||||
{ prop: 'bom_code', label: 'BOM', minWidth: '100' },
|
||||
{ prop: 'production_manager', label: '负责人', minWidth: '100' },
|
||||
{ prop: 'raw_material_cost', label: '原料成本', minWidth: '100' },
|
||||
{ prop: 'unit_total_cost', label: '单件成本', minWidth: '100' },
|
||||
{ prop: 'total_price', label: '总成本', minWidth: '100' },
|
||||
{ prop: 'inbound_date', label: '生产日期', minWidth: '120' },
|
||||
{ prop: 'detail_link', label: '详情', minWidth: '100' }
|
||||
{ prop: 'company_name', label: '所属公司', minWidth: '100', sortable: true }, // [新增]
|
||||
{ prop: 'material_name', label: '名称', minWidth: '140', sortable: true },
|
||||
{ prop: 'sku', label: 'SKU', minWidth: '110', sortable: true },
|
||||
{ prop: 'serial_number', label: '序列号', minWidth: '130', sortable: true },
|
||||
{ prop: 'qty_stock', label: '库存', minWidth: '90', sortable: true },
|
||||
{ prop: 'status', label: '状态', minWidth: '90', sortable: true },
|
||||
{ prop: 'quality_status', label: '质量', minWidth: '90', sortable: true },
|
||||
{ prop: 'spec_model', label: '规格', minWidth: '120', sortable: true },
|
||||
{ prop: 'unit', label: '单位', minWidth: '80', sortable: true },
|
||||
{ prop: 'product_photo', label: '实拍图', minWidth: '100', sortable: false },
|
||||
{ prop: 'sale_price', label: '售价', minWidth: '100', sortable: true },
|
||||
{ prop: 'order_id', label: '订单号', minWidth: '120', sortable: true },
|
||||
{ prop: 'work_order_code', label: '工单号', minWidth: '120', sortable: true },
|
||||
{ prop: 'quality_report_link', label: '质量报告', minWidth: '100', sortable: false },
|
||||
{ prop: 'inspection_report_link', label: '检测报告', minWidth: '100', sortable: false },
|
||||
{ prop: 'bom_code', label: 'BOM', minWidth: '100', sortable: true },
|
||||
{ prop: 'production_manager', label: '负责人', minWidth: '100', sortable: true },
|
||||
{ prop: 'raw_material_cost', label: '原料成本', minWidth: '100', sortable: true },
|
||||
{ prop: 'unit_total_cost', label: '单件成本', minWidth: '100', sortable: true },
|
||||
{ prop: 'total_price', label: '总成本', minWidth: '100', sortable: true },
|
||||
{ prop: 'inbound_date', label: '生产日期', minWidth: '120', sortable: true },
|
||||
{ prop: 'detail_link', label: '详情', minWidth: '100', sortable: false }
|
||||
]
|
||||
|
||||
// 列与权限Code的映射关系(数据库中的code)
|
||||
@ -834,11 +909,17 @@ const handleManagerSelect = (item: any) => {
|
||||
}
|
||||
|
||||
const fetchData = async () => {
|
||||
loading.value = true;
|
||||
loading.value = true
|
||||
try {
|
||||
const params = { ...queryParams, statuses: queryParams.statuses.join(',') }
|
||||
const res: any = await getProductList(params);
|
||||
tableData.value = res.data.items || [];
|
||||
const params = {
|
||||
...queryParams,
|
||||
statuses: queryParams.statuses.join(','),
|
||||
orderByColumn: queryParams.orderByColumn,
|
||||
isAsc: queryParams.isAsc,
|
||||
advancedFilters: queryParams.advancedFilters.length > 0 ? JSON.stringify(queryParams.advancedFilters) : ''
|
||||
}
|
||||
const res: any = await getProductList(params)
|
||||
tableData.value = res.data.items || []
|
||||
total.value = res.data.total || 0
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
@ -862,6 +943,45 @@ const resetQuery = () => {
|
||||
queryParams.material_type = ''
|
||||
queryParams.company = ''
|
||||
queryParams.page = 1
|
||||
queryParams.orderByColumn = ''
|
||||
queryParams.isAsc = ''
|
||||
queryParams.advancedFilters = []
|
||||
fetchData()
|
||||
}
|
||||
|
||||
const handleSortChange = ({ column, prop, order }: any) => {
|
||||
if (order === 'ascending') {
|
||||
queryParams.orderByColumn = prop
|
||||
queryParams.isAsc = 'true'
|
||||
} else if (order === 'descending') {
|
||||
queryParams.orderByColumn = prop
|
||||
queryParams.isAsc = 'false'
|
||||
} else {
|
||||
queryParams.orderByColumn = ''
|
||||
queryParams.isAsc = ''
|
||||
}
|
||||
queryParams.page = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user