feat(purchase): 采购列表支持关键词搜索与日期范围

背景
----
采购管理此前只有状态筛选,无法按单号/物料/申请人检索,也无法按采购
日期收窄范围。现对齐出库/报废记录的搜索语义,便于用户迁移使用习惯。

后端
----
PurchaseService.get_purchase_list 新增参数:
  keyword / search_type / start_date / end_date

search_type 取值(与出库、报废一致):
  all          单号 | 物料名称 | 规格型号 | 备注 | 申请人
  no           单号
  name         物料名称
  spec_model   规格型号
  requester    申请人

实现要点
--------
· 申请人姓名存在 SysUser.username,格式「姓名/账号」(如 韩善龙/hanshanlong),
  ilike 直接匹配整串即可命中;
· 该类字段只在 SysUser 上,故**按需 join** —— 单号/名称/规格分支不联表,
  避免无谓开销;
· 公司隔离分支也需 join SysUser,与关键词分支可能重复 join 同一目标,
  会产生笛卡尔积导致结果翻倍,故按需补 join 并用 distinct 兜底;
· 日期范围按 purchase_date 过滤(该列是 Date,无需补时分秒)。

实测:名称'充电器'→1 单,申请人'韩善龙'→21 单,日期 05-13→2 单,
      关键词不存在→0 单,状态+搜索组合→14 单。
This commit is contained in:
yueli
2026-09-10 17:41:22 +08:00
parent a4a9afb6db
commit e93107458a
2 changed files with 72 additions and 11 deletions

View File

@ -65,7 +65,13 @@ def get_purchase_list():
page = int(request.args.get('page', 1))
per_page = int(request.args.get('limit', 20))
status = request.args.get('status')
status = int(status) if status is not None else None
status = int(status) if status not in (None, '', 'all') else None
# 搜索参数(与出库/报废记录同一套语义,便于用户迁移习惯)
keyword = (request.args.get('keyword') or '').strip()
search_type = (request.args.get('search_type') or 'all').strip()
start_date = (request.args.get('start_date') or '').strip()
end_date = (request.args.get('end_date') or '').strip()
user_id = get_current_user_id()
can_view_all = _user_has_purchase_perm()
@ -74,7 +80,11 @@ def get_purchase_list():
page=page,
per_page=per_page,
requester_id=None if can_view_all else user_id,
status=status
status=status,
keyword=keyword,
search_type=search_type,
start_date=start_date,
end_date=end_date,
)
# ★ 字段级价格过滤