文件预览

member_manager.py

查看 Jf Open Pro Ai Indoor Security 技能包中的文件内容。

文件内容

scripts/member_manager.py

#!/usr/bin/env python3
"""
成员管理脚本 - 新增、删除、修改、查询成员

支持平台:JF Tech(杰峰)
"""

import argparse
import json
import sys
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError

# 导入杰峰签名工具
from jf_signature import generate_signature



def add_member(sn: str, user: str, name: str, pictures: list, uuid: str, appkey: str, 
               secret: str, authorization: str, avatar: str = None, notice: int = 1) -> dict:
    """新增成员"""
    url = "https://api-cn.jftechws.com/aisvr/v3/gateway/api/indoor/face/sample/add"
    time_millis, signature = generate_signature(uuid, appkey, secret, movecard)
    
    headers = {
        "Content-Type": "application/json",
        "uuid": uuid,
        "appKey": appkey,
        "timeMillis": time_millis,
        "signature": signature,
        "Authorization": authorization
    }
    
    body = {
        "sn": sn,
        "user": user,
        "faceSampleName": name,
        "pictureList": pictures,
        "notice": notice
    }
    
    if avatar:
        body["avatar"] = avatar
    
    req = Request(url, data=json.dumps(body).encode(), headers=headers, method="POST")
    
    try:
        with urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode())
    except HTTPError as e:
        return {"error": f"HTTP {e.code}", "message": e.read().decode()}
    except URLError as e:
        return {"error": "Network error", "message": str(e)}


def delete_member(sn: str, user: str, member_id: int, uuid: str, appkey: str, 
                  secret: str, authorization: str) -> dict:
    """删除成员"""
    url = "https://api-cn.jftechws.com/aisvr/v3/gateway/api/indoor/face/sample/delete"
    time_millis, signature = generate_signature(uuid, appkey, secret, movecard)
    
    headers = {
        "Content-Type": "application/json",
        "uuid": uuid,
        "appKey": appkey,
        "timeMillis": time_millis,
        "signature": signature,
        "Authorization": authorization
    }
    
    body = {"sn": sn, "user": user, "faceSampleId": member_id}
    req = Request(url, data=json.dumps(body).encode(), headers=headers, method="POST")
    
    try:
        with urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode())
    except HTTPError as e:
        return {"error": f"HTTP {e.code}", "message": e.read().decode()}
    except URLError as e:
        return {"error": "Network error", "message": str(e)}


def update_member(sn: str, user: str, member_id: int, name: str, pictures: list,
                  uuid: str, appkey: str, secret: str, authorization: str,
                  avatar: str = None, notice: int = None) -> dict:
    """修改成员"""
    url = "https://api-cn.jftechws.com/aisvr/v3/gateway/api/indoor/face/sample/update"
    time_millis, signature = generate_signature(uuid, appkey, secret, movecard)
    
    headers = {
        "Content-Type": "application/json",
        "uuid": uuid,
        "appKey": appkey,
        "timeMillis": time_millis,
        "signature": signature,
        "Authorization": authorization
    }
    
    body = {
        "sn": sn,
        "user": user,
        "id": member_id,
        "faceSampleName": name,
        "pictureList": pictures
    }
    
    if avatar:
        body["avatar"] = avatar
    if notice is not None:
        body["notice"] = notice
    
    req = Request(url, data=json.dumps(body).encode(), headers=headers, method="POST")
    
    try:
        with urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode())
    except HTTPError as e:
        return {"error": f"HTTP {e.code}", "message": e.read().decode()}
    except URLError as e:
        return {"error": "Network error", "message": str(e)}


def list_members(sn: str, user: str, uuid: str, appkey: str, 
                 secret: str, authorization: str, movecard: int, member_id: int = None,
                 notice: int = None, static_flag: int = None) -> dict:
    """查询成员列表"""
    url = "https://api-cn.jftechws.com/aisvr/v3/gateway/api/indoor/face/sample/list"
    time_millis, signature = generate_signature(uuid, appkey, secret, movecard)
    
    headers = {
        "Content-Type": "application/json",
        "uuid": uuid,
        "appKey": appkey,
        "timeMillis": time_millis,
        "signature": signature,
        "Authorization": authorization
    }
    
    body = {"sn": sn, "user": user}
    
    if member_id is not None:
        body["faceSampleId"] = member_id
    if notice is not None:
        body["notice"] = notice
    if static_flag is not None:
        body["staticFlag"] = static_flag
    
    req = Request(url, data=json.dumps(body).encode(), headers=headers, method="POST")
    
    try:
        with urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode())
    except HTTPError as e:
        return {"error": f"HTTP {e.code}", "message": e.read().decode()}
    except URLError as e:
        return {"error": "Network error", "message": str(e)}


def format_member_result(result: dict, action: str) -> str:
    """格式化成员操作结果"""
    if "error" in result:
        return f"❌ 错误:{result.get('error', 'Unknown')}\n{result.get('message', '')}"
    
    code = result.get("code", 0)
    if code != 2000:
        msg = result.get('msg', '')
        if code == 12504:
            return f"❌ API 错误码:{code}\n{msg}\n\n💡 设备未开通室内安防套餐,请登录开放平台绑定套餐卡"
        return f"❌ API 错误码:{code}\n{msg}"
    
    if action == "add":
        return "✅ 成员添加成功"
    elif action == "delete":
        return "✅ 成员删除成功"
    elif action == "update":
        return "✅ 成员信息更新成功"
    
    return json.dumps(result, indent=2, ensure_ascii=False)


def format_list_result(result: dict) -> str:
    """格式化成员列表结果"""
    if "error" in result:
        return f"❌ 错误:{result.get('error', 'Unknown')}\n{result.get('message', '')}"
    
    code = result.get("code", 0)
    if code != 2000:
        msg = result.get('msg', '')
        if code == 12504:
            return f"❌ API 错误码:{code}\n{msg}\n\n💡 设备未开通室内安防套餐,请登录开放平台绑定套餐卡"
        return f"❌ API 错误码:{code}\n{msg}"
    
    data = result.get("data", [])
    
    if not data:
        return "📭 暂无成员记录"
    
    output = [f"✅ 共 {len(data)} 个成员\n"]
    
    for i, member in enumerate(data, 1):
        output.append(f"👤 成员 {i}:")
        output.append(f"   ID: {member.get('id', 'N/A')}")
        output.append(f"   名称:{member.get('faceSampleName', 'N/A')}")
        output.append(f"   家人通知:{'✅' if member.get('notice') else '⏸️'}")
        output.append(f"   统计标记:{'✅' if member.get('staticFlag') else '⏸️'}")
        if member.get('avatar'):
            output.append(f"   头像:有")
        face_pics = member.get('facePics', [])
        if face_pics:
            output.append(f"   照片数:{len(face_pics)}")
        output.append("")
    
    return "\n".join(output)


def main():
    parser = argparse.ArgumentParser(description="成员管理 - 新增、删除、修改、查询成员")
    parser.add_argument("--action", required=True, 
                        choices=["add", "delete", "update", "list"], 
                        help="操作类型")
    parser.add_argument("--sn", required=True, help="设备序列号")
    parser.add_argument("--user", required=True, help="用户 ID")
    parser.add_argument("--uuid", required=True, help="开放平台用户 uuid")
    parser.add_argument("--appkey", required=True, help="应用 appKey")
    parser.add_argument("--secret", required=True, help="应用密钥")
    parser.add_argument("--auth", required=True, help="用户 token")
    
    # add/update 操作参数
    parser.add_argument("--name", help="成员名称")
    parser.add_argument("--picture", action="append", help="成员图片(base64,可多次指定)")
    parser.add_argument("--avatar", help="成员头像(base64)")
    parser.add_argument("--notice", type=int, choices=[0, 1], help="家人通知(0 关闭,1 开启)")
    
    # delete/update 操作参数
    parser.add_argument("--id", type=int, help="成员 ID")
    
    # list 操作参数
    parser.add_argument("--member-id", type=int, help="指定成员 ID(list 操作)")
    parser.add_argument("--static-flag", type=int, help="统计标记(list 操作)")
    
    parser.add_argument("--json", action="store_true", help="输出 JSON 格式")
    parser.add_argument("--verbose", "-v", action="store_true",
                        help="输出详细 curl 命令和原始响应(重要查询必须使用)")
    
    args = parser.parse_args()
    
    if args.action == "add":
        if not args.name or not args.picture:
            print("❌ add 操作需要指定 --name 和 --picture 参数")
            sys.exit(1)
        
        result = add_member(
            sn=args.sn, user=args.user, name=args.name, pictures=args.picture,
            avatar=args.avatar, notice=args.notice if args.notice is not None else 1,
            uuid=args.uuid, appkey=args.appkey, secret=args.secret, authorization=args.auth
        )
        output = format_member_result(result, "add") if not args.json else json.dumps(result, indent=2, ensure_ascii=False)
    
    elif args.action == "delete":
        if not args.id:
            print("❌ delete 操作需要指定 --id 参数")
            sys.exit(1)
        
        result = delete_member(
            sn=args.sn, user=args.user, member_id=args.id,
            uuid=args.uuid, appkey=args.appkey, secret=args.secret, authorization=args.auth
        )
        output = format_member_result(result, "delete") if not args.json else json.dumps(result, indent=2, ensure_ascii=False)
    
    elif args.action == "update":
        if not args.id or not args.name or not args.picture:
            print("❌ update 操作需要指定 --id, --name, --picture 参数")
            sys.exit(1)
        
        result = update_member(
            sn=args.sn, user=args.user, member_id=args.id, name=args.name, pictures=args.picture,
            avatar=args.avatar, notice=args.notice,
            uuid=args.uuid, appkey=args.appkey, secret=args.secret, authorization=args.auth
        )
        output = format_member_result(result, "update") if not args.json else json.dumps(result, indent=2, ensure_ascii=False)
    
    elif args.action == "list":
        result = list_members(
            sn=args.sn, user=args.user,
            member_id=args.member_id, static_flag=args.static_flag,
            uuid=args.uuid, appkey=args.appkey, secret=args.secret, authorization=args.auth
        )
        output = format_list_result(result) if not args.json else json.dumps(result, indent=2, ensure_ascii=False)
    
    print(output)


if __name__ == "__main__":
    main()