背景:出库的「领用人/客户」一直是自由文本框(create.vue 的 el-input),
后端 consumer_name 必填但内容不限。实测 1497 条出库里有 7 条领用人对不上
任何在职人员,其中就有把姓名打成「刘」这种错字 —— 手输必然产生这类问题。
而同一个表单里紧挨着的「经办人(库管)」已经是下拉选择了。
改动:
前端 outbound/create.vue
· 领用人由 el-input 改为 el-select(filterable + allow-create +
default-first-option),数据源复用统一的在职人员接口 getActiveUsers()
(与出库补发的「补发给谁」同一份,公司隔离由后端负责)。
· 选中审批单时自动带出申请人(fillConsumerFromRequest),仍可改成别人。
★ 按 applicant_id 在在职名单里**反查**姓名,而不是直接用接口返回的
applicant_name —— 后者是 '高雪/gaoxue'(后端 _get_user_name 返回完整
username),直接落库会把台账的姓名口径搞乱(实测 1497 行无一带 '/')。
· 动态模糊匹配:姓名与**拼音**都能搜。默认 filterable 只匹配 label(姓名),
输 gaoxue 匹配不到高雪,故自定义 filter-method 一并比对账号段。
· 软提示而非硬拦截:填了不在名单里的名字会显示
「「X」不在在职人员名单中,请确认没写错」。保留 allow-create 是因为
销售出库的客户可能是外部人员、没有账号,封死会让这类出库没法登记。
后端 common/users.py
· active_user_options() 增加 account 字段(username 里 '/' 之后那段拼音),
供前端拼音搜索。仍是 id/姓名/账号三项,不含邮箱、角色、部门。
★ 没有做后端强校验(拒绝非系统人员):用户明确选择「下拉为主,保留手输兜底」,
硬拦会挡住外部客户。错字的防线是"默认从名单里选 + 不在名单时给提示"。
验证(12 + 6 项断言全过):
· 39 个在职人员,每项含 id/name/account;name 是裸姓名、account 非空
· 拼音搜索:输 gaoxue / GAOXUE → 高雪;输 gao → 高前赐/高闯/高雪;输 高雪 → 高雪
· 在职人员无重名(按姓名绑定才无歧义)
· 已通过的审批单能反查到在职申请人(单 514/513/512/511/509 全部命中)
· 公司隔离:IRIS 用户 20 人只看到「石利」、LICA 用户 19 人只看到
「石利LICA」、超管 39 人 —— 跨公司同名在各自视角下不会同时出现
· 借库人员选择器(共用同一实现)仍正常,新增字段向后兼容
· 日报三天附件 490.5K/193.4K/92.3K 与 6 列结构未变;出库列表接口未受影响
· vue-tsc 与 vite build exit=0
注意:
· 历史 7 条不匹配的领用人**未改动**(其中「常国玺」疑似离职人员)。
· 前端只做了编译验证,未在浏览器实际点过 —— 下拉交互与提示样式需人工确认。
60 lines
2.6 KiB
Python
60 lines
2.6 KiB
Python
# inventory-backend/app/api/v1/common/users.py
|
||
from flask import jsonify
|
||
from flask_jwt_extended import jwt_required
|
||
|
||
from . import common_bp
|
||
|
||
|
||
def active_user_options():
|
||
"""
|
||
在职人员名单(id + 姓名 + 账号)——「选择某人」类下拉框的**共用实现**。
|
||
|
||
★ 为什么单独开一条中性路径,而不是复用 /transactions/borrow/users:
|
||
那条路径在语义上属于借库模块,出库补发、报废执行等处若直接复用,
|
||
后人读代码时会困惑「出库为什么在调借库的接口」。这里提供统一入口,
|
||
借库那条路径改为调本函数,实现只有一份。
|
||
|
||
★ 公司隔离与业务台账同口径(get_current_company_filter):
|
||
否则 A 公司的人能在选择器里看到 B 公司人员。
|
||
|
||
★ 只返回 id / 姓名 / 账号:不含邮箱、角色、部门 —— 仍是最小披露。
|
||
账号(username 里 '/' 之后那一段,如 'gaoxue')是**拼音**,
|
||
选择器靠它支持「输拼音找人」(输 gaoxue 匹配到高雪)——
|
||
这是加它的唯一原因,不是要把登录名铺开。
|
||
|
||
★ 姓名口径用 user_display_name('高雪/gaoxue' → '高雪'),
|
||
与出库/借库台账里存姓名的写法一致;否则同一人在台账里会出现两种写法。
|
||
"""
|
||
from app.utils.decorators import get_current_company_filter
|
||
from app.models.system import SysUser
|
||
from app.services.trans_service import user_display_name
|
||
|
||
company_limit = get_current_company_filter()
|
||
query = SysUser.query.filter(SysUser.status == 'active')
|
||
if company_limit is not None:
|
||
# 与 borrow_service.get_request_list 一致:SysUser.department 即公司维度
|
||
query = query.filter(SysUser.department == company_limit)
|
||
|
||
out = []
|
||
for u in query.order_by(SysUser.username).all():
|
||
raw = str(u.username or '')
|
||
out.append({
|
||
'id': u.id,
|
||
'name': user_display_name(u),
|
||
'account': raw.split('/')[-1] if '/' in raw else '',
|
||
})
|
||
return out
|
||
|
||
|
||
@common_bp.route('/active-users', methods=['GET'])
|
||
@jwt_required()
|
||
def get_active_users():
|
||
"""
|
||
在职人员名单,供借出 / 转交 / 归还 / 出库补发等多个页面的选择器共用。
|
||
|
||
★ 无 permission_required,仅要求登录:
|
||
同一份名单要被多个页面共用,绑定其中任一权限码都会让其他页面 403;
|
||
且只暴露 id 与姓名(与 /auth/users/approvers 同一处理方式)。
|
||
"""
|
||
return jsonify({'code': 200, 'msg': 'success', 'data': active_user_options()})
|