From 1c58789fd9227aebb3ae2149290d860695f3f993 Mon Sep 17 00:00:00 2001 From: yueli Date: Thu, 17 Sep 2026 10:30:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(borrow):=20=E6=96=B0=E5=A2=9E=E3=80=8C?= =?UTF-8?q?=E5=BE=85=E6=88=91=E6=8E=A5=E6=94=B6=E3=80=8D=E8=BD=AC=E4=BA=A4?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GET /api/v1/transactions/borrow/transfer/pending-count -> { count: X } 用途:双向握手引入后,发起方提交了转交,接收人若不来借还记录页主动查看就 完全处于盲区 —— 物品挂着「待接收」,责任悬空。该接口供前端做全局强提醒。 设计 ---- · 刻意做成极轻量:一次 count,不联表、不解析物料名。轮询接口必须便宜, 否则会从「提醒」变成「后台噪音」。 · 无 permission_required:接收人可能是普通员工,待办提醒必须人人可见 (与 accept/reject 同级 —— 员工处置自己名下资产,非库管职权)。 · user_id 为 None / 非法时返回 0 而不是抛错:提醒类接口不该因边界输入 500。 路由无冲突 ---- 「transfer」匹配不了 ,「pending-count」也匹配不了 ,Werkzeug 按转换器精确分派。实测: GET /borrow/transfer/pending-count -> 401(已注册且受 JWT 保护) GET /borrow/11/transfer -> 405(路径命中但方法不符,证无冲突) 验证(9 项断言全通过) ---- 发起后接收人计数 +1、非接收人不变;拒绝/接收后均回落; None 与非法 user_id 返回 0 不报错;库存零副作用、数据零残留。 --- inventory-backend/app/api/v1/transactions.py | 27 +++++++++++++++++++ .../app/services/trans_service.py | 18 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/inventory-backend/app/api/v1/transactions.py b/inventory-backend/app/api/v1/transactions.py index b75a8b8..1925230 100644 --- a/inventory-backend/app/api/v1/transactions.py +++ b/inventory-backend/app/api/v1/transactions.py @@ -737,6 +737,33 @@ def reject_borrow_transfer(transfer_id): return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500 +# --- 待我接收的转交数量(全局待办提醒)--- +@trans_bp.route('/borrow/transfer/pending-count', methods=['GET']) +@jwt_required() +def get_pending_transfer_count(): + """ + 待我接收的转交数量,供前端全局待办强提醒使用。 + + ★ 无 permission_required:接收人可能是普通员工,待办提醒必须人人可见 + (与 accept/reject 同级的理由 —— 这是员工处置自己名下资产,非库管职权)。 + + ★ 路由不与 /borrow//transfer 等冲突: + 「transfer」无法匹配 ,「pending-count」也无法匹配 + ,Werkzeug 会按转换器精确分派。 + """ + try: + count = TransService.count_pending_transfers(get_jwt_identity()) + return jsonify({ + 'code': 200, + 'msg': 'success', + 'count': count, + 'data': {'count': count}, + }), 200 + except Exception as e: + traceback.print_exc() + return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500 + + # --- 借出单的流转历史(转交链 + 逐次归还)--- @trans_bp.route('/borrow//history', methods=['GET']) @jwt_required() diff --git a/inventory-backend/app/services/trans_service.py b/inventory-backend/app/services/trans_service.py index 649af5f..20f8767 100644 --- a/inventory-backend/app/services/trans_service.py +++ b/inventory-backend/app/services/trans_service.py @@ -726,6 +726,24 @@ class TransService: raise e return transfer + @staticmethod + def count_pending_transfers(user_id): + """ + 「待我接收」的转交数量 —— 供全局待办提醒在初始化与轮询时调用。 + + ★ 刻意做成极轻量:一次 count,不联表、不解析物料名。 + 轮询接口必须便宜,否则会从「提醒」变成「后台噪音」。 + """ + if user_id is None: + return 0 + try: + return TransBorrowTransfer.query.filter( + TransBorrowTransfer.to_user_id == int(user_id), + TransBorrowTransfer.status == TRANSFER_STATUS_PENDING, + ).count() + except (TypeError, ValueError): + return 0 + @staticmethod def get_transfer_history(borrow_id): """某条借出记录的转交历史(按时间正序,便于还原 A→B→C 链路)"""