Skill: fjjzy/baidu-hair-salon (version 1.0.0)

--- name: baidu-hair-salon description: 当用户说"预约理发"、"剪头发"、"预约发型师"、"查看预约记录"时触发。用于百度理发店预约。 author: Jarvis (自建) created: 2026-03-25 --- # 百度理发店预约 预约百度理发店，支持查看店铺、发型师、选择时间、提交预约、查询预约记录。 ## Tools 先 `cd` 到 skill 根目录，再 `cd scripts/`： ```bash cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py shops cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py services cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py staff [shop_id] cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py dates cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py slots <staff_id> <date> cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py book <staff_id> <staff_name> <date> <time> <phone> [project] cd ~/.openclaw/skills/baidu-hair-salon/scripts/ && python3 booking.py list [phone] ``` ## 预约流程 1. **读取上次偏好** → 从 `skills.entries.baidu-hair-salon` 获取上次选择的店铺/发型师/服务，询问是否继续使用。预约完成/中断：必须自动保存用户偏好。 2. **问用户选择哪家店** → 调用 `shops` - 展示店铺列表（店名 + 地址） - 用户选定后记录 shop_id 3. **查询发型师和空闲时间** → 调用 `staff <shop_id>` 和 `dates` - 获取可预约日期范围 - **对每个发型师，查询今天和明天的空闲时间段** - 一起展示给用户 4. **用户选择发型师和空闲时间** 5. **问用户选择服务项目** → 调用 `services` - 展示可选服务（理发、烫发、染发等） - 用户选定后记录 serve_type 6. **确认手机号**（必填）→ 调用 `book` 7. **保存本次选择** → 更新 openclaw.json 中的偏好（店铺、发型师、服务） 8. 展示预约结果 ## 回复格式示例（**严格按照此格式输出，禁止省略空行**） **店铺列表：** ``` 目前支持的店铺： 1. 百度大厦店 地址：百度大厦B1层AE区淋浴间对面 营业时间：周一至周五 9:00-21:00 电话：010-59923770 2. 百度科技园1号楼店 地址：百度科技园1号楼B1层食堂和便利店旁 营业时间：周一至周五 9:00-21:00 电话：010-59923543 3. 百度科技园4号楼店 地址：百度科技园4号楼负一层下沉广场 营业时间：周一至周五 9:00-21:00 电话：010-59922259 请回复数字选择哪家店 ``` **发型师 + 空闲时间：** ``` 可选Tony： 1. 李东 - 资深发型师 今天 03-25（周三）可约：10:00、14:00、16:00 明天 03-26（周四）可约：10:00、14:00 2. 王芳 - 总监 今天 03-25（周三）可约：11:00、15:00 明天 03-26（周四）可约：09:00、13:00 请选择发型师和时间 ``` **服务项目：** ``` 可选服务： 1. 剪发 2. 烫发 3. 染发 4. 护理 请回复数字选择 ``` **预约成功：** ``` ✅ 预约成功，请提前到达哦！ - 店铺：XXX店 - 地址：XXX - 电话：XXX - 发型师：XXX - 日期：XXXX-XX-XX - 时间：XX:XX - 项目：男发精剪 ``` ## 用户信息存储 **首次使用时**：询问用户手机号和姓名。 **预约完成/中断**：必须自动保存用户偏好到 `~/.openclaw/openclaw.json` 的 `skills.entries.baidu-hair-salon` 下： ```json { "skills": { "entries": { "baidu-hair-salon": { "default_phone": "用户手机号", "default_person": "用户姓名", "last_shop_id": "店铺ID", "last_shop_name": "店铺名称", "last_staff_id": "发型师ID", "last_staff_name": "发型师姓名", "last_service": "服务项目" } } } } ``` **后续使用时**：直接读取配置，已有偏好则询问是否继续使用。 ## Gotchas - **手机号必填**：预约前必须确认用户手机号 - **先选店铺和服务项目**：每次预约前先问用户哪家店、什么服务 - **发型师 ID 是数字**：调用 slots/book 时用 staff_id - **日期格式**：YYYY-MM-DD - **时间格式**：HH:MM - 店铺信息（地址、电话、营业时间）可从 `shops` 结果获取 - 服务项目可从 `services` 结果获取 - **用户偏好会保存到 openclaw.json**：分享 skill 时记得清除这些敏感信息 - **输出格式必须严格遵循示例**： - 店铺列表中**每块店铺之间必须空一行** - **禁止使用 emoji**（地址、电话、营业时间等都不用 emoji） - 信息分段清晰，参考上面的示例

path: scripts/booking.py
content: #!/usr/bin/env python3
"""
理发店预约工具
支持：查看发型师、获取日期、获取时间段、提交预约、查询预约记录
"""

import os
import json as json_module
import requests
import json
import sys
from datetime import datetime, timedelta

BASE_URL = "http://goldsalon999.fun:8888/hair-salon/salon/serve"

# 从 openclaw.json 读取偏好
OPENCLAW_CONFIG = os.path.expanduser("~/.openclaw/openclaw.json")

def load_prefs():
    """从 openclaw.json 加载用户偏好"""
    try:
        with open(OPENCLAW_CONFIG, "r") as f:
            config = json_module.load(f)
        entries = config.get("skills", {}).get("entries", {})
        hair = entries.get("baidu-hair-salon", {})
        return {
            "phone": hair.get("default_phone", ""),
            "person": hair.get("default_person", ""),
            "shop_id": hair.get("last_shop_id", ""),
            "shop_name": hair.get("last_shop_name", ""),
            "staff_id": hair.get("last_staff_id", ""),
            "staff_name": hair.get("last_staff_name", ""),
            "service": hair.get("last_service", ""),
        }
    except Exception:
        return {
            "phone": "",
            "person": "",
            "shop_id": "",
            "shop_name": "",
            "staff_id": "",
            "staff_name": "",
            "service": "",
        }

def save_prefs(prefs):
    """保存用户偏好到 openclaw.json"""
    try:
        with open(OPENCLAW_CONFIG, "r") as f:
            config = json_module.load(f)
    except Exception:
        config = {}

    if "skills" not in config:
        config["skills"] = {}
    if "entries" not in config["skills"]:
        config["skills"]["entries"] = {}
    config["skills"]["entries"]["baidu-hair-salon"] = prefs

    with open(OPENCLAW_CONFIG, "w") as f:
        json_module.dump(config, f, ensure_ascii=False, indent=2)

DEFAULT_PHONE = ""
DEFAULT_PERSON = ""
DEFAULT_SHOP_ID = ""
SHOP_NAME = ""
SHOP_PHONE = ""

HEADERS = {
    "Accept": "*/*",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "DNT": "1",
    "Origin": "http://goldsalon999.fun:9008",
    "Pragma": "no-cache",
    "Referer": "http://goldsalon999.fun:9008/",
    "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5) AppleWebKit/537.36"
}


def get_staff_list(shop_id=None):
    """获取发型师列表"""
    shop_id = shop_id or DEFAULT_SHOP_ID
    url = f"{BASE_URL}/userList?shopId={shop_id}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def get_shop_list():
    """获取店铺列表"""
    url = f"{BASE_URL}/shopList?shopType=1"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def get_service_types(serve_type="hair"):
    """获取服务项目类型"""
    url = f"{BASE_URL}/serviceType?serveType={serve_type}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def get_date_list():
    """获取可预约日期列表"""
    url = f"{BASE_URL}/dateList"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def get_time_slots(staff_id, book_date, serve_type="hair"):
    """获取指定日期和发型师的可预约时间段"""
    url = f"{BASE_URL}/timeSlots?serveType={serve_type}&staffId={staff_id}&bookDate={book_date}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def book_appointment(staff_id, staff_name, book_date, book_time, project="男发精剪",
                     service_time=0.5, book_person=DEFAULT_PERSON,
                     book_phone=DEFAULT_PHONE, serve_type="hair", period=1):
    """提交预约"""
    url = f"{BASE_URL}/book"

    payload = {
        "project": project,
        "serviceTime": service_time,
        "shopName": SHOP_NAME,
        "shopPhone": SHOP_PHONE,
        "staffId": staff_id,
        "staffName": staff_name,
        "bookDate": book_date,
        "bookTime": book_time,
        "bookPerson": book_person,
        "bookPhone": book_phone,
        "shopType": "1",
        "serveType": serve_type,
        "period": period
    }

    headers = HEADERS.copy()
    headers["Content-Type"] = "application/json"

    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def get_book_list(phone=DEFAULT_PHONE):
    """查询预约记录"""
    url = f"{BASE_URL}/bookList?bookPhone={phone}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def main():
    # 加载偏好
    prefs = load_prefs()
    global DEFAULT_PHONE, DEFAULT_PERSON, DEFAULT_SHOP_ID, SHOP_NAME, SHOP_PHONE
    DEFAULT_PHONE = prefs["phone"]
    DEFAULT_PERSON = prefs["person"]

    if len(sys.argv) < 2:
        print("用法: python booking.py <命令> [参数]")
        print("")
        print("命令:")
        print("  shops                    获取店铺列表")
        print("  services [serve_type]    获取服务项目列表（默认 hair）")
        print("  staff [shop_id]          获取发型师列表（可选指定店铺）")
        print("  dates                    获取可预约日期")
        print("  slots <staff_id> <date> 获取时间段")
        print("  book <staff_id> <staff_name> <date> <time> <phone> [project]  提交预约")
        print("  list [phone]             查询预约记录")
        print("  pref-get                 查看当前偏好")
        print("  pref-set <phone> <person> [shop_id] [shop_name] [staff_id] [staff_name] [service]")
        sys.exit(1)

    cmd = sys.argv[1]

    if cmd == "shops":
        result = get_shop_list()
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif cmd == "services":
        serve_type = sys.argv[2] if len(sys.argv) > 2 else "hair"
        result = get_service_types(serve_type)
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif cmd == "staff":
        shop_id = sys.argv[2] if len(sys.argv) > 2 else None
        result = get_staff_list(shop_id)
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif cmd == "dates":
        result = get_date_list()
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif cmd == "slots":
        if len(sys.argv) < 4:
            print("用法: python booking.py slots <staff_id> <date>")
            sys.exit(1)
        staff_id = sys.argv[2]
        date = sys.argv[3]
        result = get_time_slots(staff_id, date)
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif cmd == "book":
        if len(sys.argv) < 6:
            print("用法: python booking.py book <staff_id> <staff_name> <date> <time> <phone> [project]")
            sys.exit(1)
        staff_id = int(sys.argv[2])
        staff_name = sys.argv[3]
        date = sys.argv[4]
        time = sys.argv[5]
        phone = sys.argv[6]
        project = sys.argv[7] if len(sys.argv) > 7 else "男发精剪"
        result = book_appointment(staff_id, staff_name, date, time, project, book_phone=phone)
        print(json.dumps(result, ensure_ascii=False, indent=2))

        # 预约成功则保存偏好
        if result.get("code") == 200:
            # 尝试从 booking.py 内部获取店铺信息，这里从参数/环境推断
            save_prefs({
                "default_phone": phone,
                "default_person": prefs.get("person", ""),
                "last_shop_id": prefs.get("shop_id", ""),
                "last_shop_name": prefs.get("shop_name", ""),
                "last_staff_id": str(staff_id),
                "last_staff_name": staff_name,
                "last_service": project,
            })
            print(f"\n[偏好已保存] phone={phone}, staff={staff_name}, project={project}")

    elif cmd == "list":
        phone = sys.argv[2] if len(sys.argv) > 2 else DEFAULT_PHONE
        result = get_book_list(phone)
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif cmd == "pref-get":
        print(json.dumps(prefs, ensure_ascii=False, indent=2))

    elif cmd == "pref-set":
        if len(sys.argv) < 4:
            print("用法: python booking.py pref-set <phone> <person> [shop_id] [shop_name] [staff_id] [staff_name] [service]")
            sys.exit(1)
        phone = sys.argv[2]
        person = sys.argv[3]
        shop_id = sys.argv[4] if len(sys.argv) > 4 else ""
        shop_name = sys.argv[5] if len(sys.argv) > 5 else ""
        staff_id = sys.argv[6] if len(sys.argv) > 6 else ""
        staff_name = sys.argv[7] if len(sys.argv) > 7 else ""
        service = sys.argv[8] if len(sys.argv) > 8 else ""
        save_prefs({
            "default_phone": phone,
            "default_person": person,
            "last_shop_id": shop_id,
            "last_shop_name": shop_name,
            "last_staff_id": staff_id,
            "last_staff_name": staff_name,
            "last_service": service,
        })
        print("偏好已保存")
        print(json.dumps(load_prefs(), ensure_ascii=False, indent=2))

    else:
        print(f"未知命令: {cmd}")
        sys.exit(1)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)