feat(records): 出库/借还记录统一高级搜索版式

三个记录页(出库/借还/报废)此前搜索区形态各异:出库用裸 div + 分散样式,
借还缺日期范围,报废只有 SKU 输入框。现统一为 el-form :inline="true" +
.filter-form 版式,并补齐缺失的过滤维度。

借还记录(新增日期范围能力):
  · 后端 get_records 增加 start_date/end_date 参数,按「借出时间」过滤;
  · 边界补全时分秒(YYYY-MM-DD → 当日 00:00:00 / 23:59:59),
    与出库记录同口径,解决零点截断导致当天记录漏查的问题;
  · API 层透传两个新参数。

出库记录:
  · 版式统一为 inline 表单,日期选择器加 label;
  · 新增「重置」按钮;
  · 搜索类型切换由 500ms 防抖改为立即查询。

借还记录:
  · 新增「重置」按钮;搜索类型/状态切换改为立即查询(取消防抖)。

实测(SUPER_ADMIN):
  报废 全部/单号/SKU/操作人/物料名/日期 六类过滤均 200 且命中正确;
  借还 无过滤 52 单 / 本月 18 单 / 空区间 0 单(日期过滤生效);
  出库 无过滤 395 单 / SKU 277 / 姓名 7 / 物料名 16 / 单号 OUT-2026 命中 395。
This commit is contained in:
yueli
2026-09-10 12:06:08 +08:00
parent 23a7fc65f1
commit c35ec9a659
4 changed files with 187 additions and 71 deletions

View File

@ -1,33 +1,54 @@
<template>
<div v-if="userStore.hasPermission('op_records')" class="app-container">
<div class="filter-container">
<el-radio-group v-model="status" @change="fetchData" style="margin-right: 20px">
<el-radio-button label="all">全部</el-radio-button>
<el-radio-button label="borrowed">未归还</el-radio-button>
<el-radio-button label="returned">已归还</el-radio-button>
</el-radio-group>
<!-- ★ 高级搜索:与出库记录 / 报废记录统一版式 -->
<el-form :inline="true" class="filter-form" @submit.prevent>
<el-form-item>
<el-radio-group v-model="status" @change="handleSearchImmediate">
<el-radio-button label="all">全部</el-radio-button>
<el-radio-button label="borrowed">未归还</el-radio-button>
<el-radio-button label="returned">已归还</el-radio-button>
</el-radio-group>
</el-form-item>
<el-input
v-model="keyword"
placeholder="请输入关键词"
style="width: 250px"
clearable
@input="debouncedSearch"
@clear="handleClearSearch"
>
<template #prepend>
<el-select v-model="searchType" placeholder="类型" style="width: 110px" @change="debouncedSearch">
<el-option label="全部" value="all" />
<el-option label="单号" value="no" />
<el-option label="借用人" value="name" />
<el-option label="SKU" value="sku" />
<el-option label="物料名称" value="material_name" />
<el-option label="规格型号" value="spec_model" />
</el-select>
</template>
</el-input>
<el-button type="primary" @click="fetchData">查询</el-button>
</div>
<el-form-item label="搜索">
<el-input
v-model="keyword"
placeholder="输入关键词"
style="width: 240px"
clearable
@input="debouncedSearch"
@clear="handleClearSearch"
>
<template #prepend>
<el-select v-model="searchType" placeholder="类型" style="width: 110px" @change="handleSearchImmediate">
<el-option label="全部" value="all" />
<el-option label="单号" value="no" />
<el-option label="借用人" value="name" />
<el-option label="SKU" value="sku" />
<el-option label="物料名称" value="material_name" />
<el-option label="规格型号" value="spec_model" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item label="借出日期">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 260px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="fetchData">查询</el-button>
<el-button @click="resetFilter">重置</el-button>
</el-form-item>
</el-form>
<el-table
:data="list"
@ -262,6 +283,7 @@ const total = ref(0)
const status = ref('borrowed')
const keyword = ref('')
const searchType = ref('all')
const dateRange = ref<string[]>([])
const page = ref(1)
const loading = ref(false)
@ -329,15 +351,20 @@ const confirmScrap = async () => {
const fetchData = async () => {
loading.value = true
try {
const params: any = {
page: page.value,
status: status.value,
keyword: keyword.value,
search_type: searchType.value
}
if (dateRange.value && dateRange.value.length === 2) {
params.start_date = dateRange.value[0]
params.end_date = dateRange.value[1]
}
const res = await request({
url: '/v1/transactions/records',
method: 'get',
params: {
page: page.value,
status: status.value,
keyword: keyword.value,
search_type: searchType.value
}
params
})
// ★ 按 borrow_no 分组聚合为主子表结构
@ -371,6 +398,23 @@ const handlePage = (val: number) => {
fetchData()
}
// 立即查询(状态/类型切换用,取消防抖)
const handleSearchImmediate = () => {
if (debounceTimer) clearTimeout(debounceTimer)
page.value = 1
fetchData()
}
const resetFilter = () => {
if (debounceTimer) clearTimeout(debounceTimer)
status.value = 'borrowed'
keyword.value = ''
searchType.value = 'all'
dateRange.value = []
page.value = 1
fetchData()
}
// ★ 新增:格式化预计归还时间及倒计时逻辑(交通灯预警系统)
const formatExpectedTime = (timeStr: string) => {
if (!timeStr) return { text: '无限期', diffText: '', style: {} }
@ -418,5 +462,15 @@ onBeforeUnmount(() => {
})
</script>
<style>
<style scoped>
/* ★ 统一高级搜索版式(与出库记录 / 报废记录一致) */
.filter-form {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.filter-form :deep(.el-form-item) {
margin-bottom: 0;
margin-right: 12px;
}
</style>