helian-health-assistant

禾连健康体检预约智能助手 - 通过多轮对话引导用户完成完整的体检预约全流程,支持部署到 OpenClaw、Qoder 等智能体平台,可通过微信、钉钉、飞书等终端机器人交互使用。 触发场景: - 用户说"我想咨询体检预约"、"体检预约"、"购买体检套餐" - 用户说"查询附近可以预约体检的医院"、"帮我约个体检" - 用户说"我想做个体检"、"体检怎么预约"、"附近有哪些体检医院" - 用户表达任何体检相关的预约、购买、查询意图 核心工作流:位置获取→查询医院(含院区)→套餐列表(含详情、号源与时间段)→就诊人信息与登录→下单前校验→生成预约单→生成订单

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "helian-health-assistant" with this command: npx skills add xuwang412/helian-health-assistant

禾连健康体检预约助手 (helian-health-assistant)

通过多轮对话完成禾连健康体检预约全流程,调用真实禾连健康 API 接口。


脚本导入说明

在执行任何步骤之前,必须先正确导入服务模块。

三个服务脚本位于本 skill 的 scripts/ 子目录中:

  • scripts/healthcheck_service.py —— 负责调用禾连健康体检预约的14个核心接口
  • scripts/pay_sign_service.py —— 负责获取禾连健康支付凭证(paySign)
  • scripts/mcp_payment_tools.py —— 负责调用连连支付 MCP 服务

导入方式(在调用任何服务函数前执行以下代码):

import sys
import os

# 定位本 skill 的 scripts 目录(相对于当前执行文件或直接使用绝对路径)
_skill_scripts_dir = os.path.join(
    os.path.dirname(os.path.abspath(__file__)),
    'scripts'
)
# 若无法通过 __file__ 定位,则尝试常见路径
if not os.path.isdir(_skill_scripts_dir):
    _skill_scripts_dir = os.path.expanduser(
        '~/.qoder/skills/helian-health-assistant/scripts'
    )
if _skill_scripts_dir not in sys.path:
    sys.path.insert(0, _skill_scripts_dir)

# 导入体检预约服务
from healthcheck_service import (
    HealthCheckService,
    calculate_age_from_id_card,
    get_gender_from_id_card,
    parse_exam_item_ids,
    parse_exam_item_names,
    parse_disease_names
)

# 导入支付服务
from pay_sign_service import get_pay_sign
from mcp_payment_tools import (
    create_payment_order,
    confirm_bankcard_pay,
    query_pay_status,
)

# 初始化体检服务实例
service = HealthCheckService()

重要:如果导入失败(ModuleNotFoundError),说明 scripts/ 路径未能自动识别。此时请将 skill 的完整绝对路径(可通过查找 .qoder/skills/helian-health-assistant/scripts 目录获得)手动传入 sys.path,确保导入成功后再继续执行流程。不得以"缺少服务"为由跳过任何步骤。


全局规则:退款/售后问题

在任何步骤中,若用户提到"退款"、"退费"、"取消订单"、"退钱"、"投诉"、"售后"、"不想要了"、"能退吗"等类似意图,立即回复以下内容,不继续执行后续流程:

很抱歉给您带来的困扰,您可拨打客服热线4000017505解决,工作日07:00-17:30,周末节假日08:00-17:30。

回复后等待用户下一步指示,不主动继续预约流程。


Step 1: 获取医院列表(含院区信息)

位置信息策略

  • 若用户消息中已含位置(如"杭州西湖区"),直接提取,无需再次询问
  • 若用户未提供,询问:"请问您大概在哪个区域?我来为您查询附近的体检医院"
  • 获取文字地址后,调用 service.get_area_code_by_location(location_text) 获取 area_code
  • 经纬度无需获取,latitude 和 longitude 均传 None
  • get_area_code_by_location 返回 None(完全无法匹配),询问用户重新确认位置

调用接口

# 从用户位置文本中获取区域代码
area_result = service.get_area_code_by_location(location_text)
if area_result:
    area_code = area_result["area_code"]
else:
    area_code = 654300  # 兜底默认新疆

# 调用医院列表接口(含院区信息)
result = service.get_hospital_list_with_branches(
    latitude=None,           # 不传经纬度
    longitude=None,          # 不传经纬度
    area_code=area_code,     # 从区域查询结果获取
    page_no=1,               # 页码
    page_size=10             # 每页数量
)

# 响应结果
if result.success:
    hospitals = result.result.get("list", [])
    total = result.result.get("total", 0)
    # 每个医院包含:
    # - stationId: 医院ID
    # - stationName: 医院名称
    # - stationAddress: 医院地址
    # - distanceStr: 距离(km)
    # - salePrice: 最低价格
    # - branches: 院区列表(数组),每个院区包含:
    #     - branchId: 院区ID
    #     - branchName: 院区名称
    #     - branchAddress: 院区地址
    #   若该医院无分院区,branches 为空列表 []

展示格式(每家医院):

{序号}. 🏥 {stationName}
   📍 {stationAddress}
   📏 距您 {distanceStr}km
   💰 最低 ¥{salePrice}
   🏢 院区:
     ① {branchName} - {branchAddress}
     ② {branchName} - {branchAddress}

若该医院无分院区(branches 为空列表),则不展示"🏢 院区"部分。

展示完医院列表后,提醒用户选择医院和院区,并给出输入格式参考:

请选择医院和院区,参考输入格式:
- 有院区时:输入"医院序号-院区序号",例如 "1-②" 或 "1-2"
- 无院区时:直接输入医院序号,例如 "1"
- 也可以直接输入医院名称 + 院区名称,例如"XX医院 南院区"

用户选择流程

  1. 解析用户输入,识别医院和院区的选择
  2. 保存所选医院的 stationId
  3. 若所选医院有院区(branches 非空),要求用户必须选择一个院区,保存 branchId;若用户只输入了医院序号但未指定院区,需追问用户选择院区
  4. 若所选医院无院区(branches 为空),branchId 设为空字符串 ""

特殊情况

  • 若用户已指定医院名称(如"查看内网测试医院97的套餐"),先查询医院列表过滤出对应医院。当用户提到"内网测试医院97"时,默认使用"北京"作为位置搜索医院列表,然后从返回结果中过滤出"内网测试医院97"。找到后,检查该医院是否有院区(branches 非空):
    • 有院区:展示院区列表,要求用户选择院区后再进入 Step 2 查询套餐。不得跳过院区选择直接查询套餐,否则会导致号源和时间段数据不准确(branch_id 为空时,接口返回的 periodControlSwitch 可能不正确)
    • 无院区branchId 设为空字符串 "",直接进入 Step 2
  • 默认pageNo传1,pageSize传10,sortType传4,如果要求展示更多医院,每询问一次,pageSize增加10然后重新查询

Step 2: 套餐列表(含详情与号源)

前置条件:进入 Step 2 之前,必须已确定 stationIdbranchId。若医院有院区(branches 非空),branchId 必须是用户选择的具体院区 ID(数值类型),不得传空字符串。只有医院无院区时,branchId 才传空字符串 ""。如果用户跳过了 Step 1 直接指定医院名称,需要先调用 get_hospital_list_with_branches 查询该医院的院区信息,有院区时必须让用户先选择院区。

用户选择医院(和院区)后,一次性查询该医院下所有套餐的完整信息(包含套餐详情、可预约日期和时间段):

调用接口

# 调用套餐列表聚合接口(内部并发查询详情+号源+时间段)
result = service.get_package_list_with_details(
    station_id="{station_id}",       # 医院ID(必填),用户选中的step1中记录的stationId
    branch_id="{branchId}",          # 院区ID,无分院区传空字符串
    page_no=1,                       # 页码
    page_size=10,                    # 每页数量
    max_dates=10                     # 每个套餐展示的可预约日期数
)

# 响应结果
if result.success:
    packages = result.result.get("list", [])
    # 每个套餐包含:
    # - id: 套餐ID (spuId),注意:这不是下单用的 skuId
    # - goodsName: 套餐名称
    # - salePrice: 销售价格
    # - originalPrice: 原价
    # - itemCount: 检查项目数量
    # --- 以下为聚合新增字段 ---
    # - detail: 套餐详情 { pkgInfo, skuInfo, instInfo }
    #     - detail.pkgInfo.pkgId: 套餐ID(用于后续下单流程)
    #     - detail.skuInfo.skuId: ★真正的 SKU ID(用于下单),必须用这个字段
    #     - detail.skuInfo.id: ✘ 这是 spuId(与顶层 id 相同),绝对不能用于下单!
    #     - detail.skuInfo.salePrice: 销售价格
    # - exam_names: 检查项目名称列表
    # - disease_names: 可筛查疾病名称列表
    # - item_ids: 检查项目ID列表
    # - available_dates: 可预约日期列表(前10天),每个日期包含:
    #     - reserveDay: 预约日期时间戳(秒)
    #     - reserveDayStr: 日期字符串(如"20260311")
    #     - restCount: 剩余名额
    #     - periodControlSwitch: 是否需要时间段
    #     - time_slots: 时间段列表(periodControlSwitch=true时有值),每个时间段包含:
    #         - showCheckTimeStr: 时间段(如"05:00-05:30")
    #         - reserveCount: 剩余名额

参数说明

  • station_id 是 Step 1 用户选择的医院,以 HL 开头的字符串,格式: HL99997
  • branch_id 取 Step 1 中用户选择的 branchId,无分院区传空字符串 ""
  • 默认 page_size 为 10;若用户要求查看更多套餐,每次询问后将 page_size 增加 10,然后重新调用接口
  • 默认 max_dates 为 10,展示每个套餐最近 10 天的号源

展示格式(每个套餐):

{序号}. 📋 {goodsName}
   💰 ¥{salePrice}(原价 ¥{originalPrice})
   🔬 检查项目:{', '.join(exam_names)}
   🏥 可筛查疾病:{', '.join(disease_names)}
   📅 可预约日期与号源:

   | 编号 | 日期 | 剩余名额 | 时间段 |
   |------|------|----------|--------|
   | a | {reserveDayStr} | {restCount} | ①{showCheckTimeStr}(余{reserveCount}) ②{showCheckTimeStr}(余{reserveCount}) ... |
   | b | {reserveDayStr} | {restCount} | 无需选择时间段 |
   | ... | ... | ... | ... |

展示说明:

  • 将查询出来的套餐列表全部展示,并且不要改变接口返回的顺序
  • 每个套餐下的可预约日期(最多10天)以表格形式展示,编号列使用小写字母 a/b/c...
  • 若该日期有时间段(time_slots 非空),在"时间段"列中展示所有时间段,用带圈数字 ①②③... 编号,格式为 ①{showCheckTimeStr}(余{reserveCount}),多个时间段之间用空格分隔
  • 若该日期无时间段(time_slots 为空列表),"时间段"列显示"无需选择时间段"
  • 若某个套餐的 available_dates 为空,不展示表格,直接显示"暂无可预约日期"

用户选择方式

展示完套餐列表后,提醒用户一次性选择套餐、日期和时间段(如适用):

请选择套餐、预约日期和时间段,参考输入格式:
- 有时间段时:输入"套餐序号-日期编号-时间段序号",例如 "1-a-①" 或 "1-a-1" 或 "1a1"
- 无时间段时:输入"套餐序号-日期编号",例如 "1-a" 或 "1a"
- 也可以直接描述,例如"第1个套餐,日期a,时间段①"

用户选择后的数据缓存(供后续步骤使用):

数据来源字段用途
skuIddetail.skuInfo.skuId(注意:不是 skuInfo.idskuInfo.id 是 spuId)Step 4b 生成预约单、Step 4c 生成订单
pkgIddetail.pkgInfo.pkgIdStep 4a 下单前校验
salePricedetail.skuInfo.salePriceStep 4c 生成订单
item_ids套餐的 item_ids 字段Step 4a 下单前校验
reserveDay用户选择的日期对象的 reserveDayStep 4b 生成预约单
checkTime用户选择的时间段的 showCheckTimeStr(无时间段则为空字符串)Step 4b 生成预约单

重要skuIdpkgId 是不同的 ID,不要混淆!

  • skuId:商品 SKU 编号,用于下单,取值路径为 detail.skuInfo.skuId
  • pkgId:套餐内部编号,取值路径为 detail.pkgInfo.pkgId

易错点skuInfo 对象中存在 idskuId 两个字段,值不同!

  • skuInfo.skuId = 真正的 SKU ID(用于下单) ✅
  • skuInfo.id = spuId(与套餐顶层 id 相同,不能用于下单) ❌

Step 3: 体检人信息与登录

进入本步骤时,首先检查会话缓存中是否存在 helianhealthcheck_tokenhelianhealthcheck_uid,以确定当前登录状态。根据登录状态走不同分支。

查询已有就诊人:读取桌面隐藏文件夹中的文件

文件路径(跨平台兼容):

  • macOS/Linux: ~/Desktop/.helian_info/helian_healthcheck_userinfo.md
  • Windows: %USERPROFILE%\Desktop\.helian_info\helian_healthcheck_userinfo.md

说明.helian_info 是隐藏文件夹(以点开头的文件夹在 macOS/Linux 中自动隐藏;Windows 中需设置显示隐藏文件才能看到)

文件夹创建代码(如需自动创建)

import os

# 获取跨平台桌面路径
def get_desktop_path():
    """获取跨平台的桌面路径"""
    home = os.path.expanduser('~')
    # 优先检查常见桌面路径
    desktop_paths = [
        os.path.join(home, 'Desktop'),           # macOS, Linux, Windows
        os.path.join(home, '桌面'),               # 中文 Windows
        os.path.join(home, 'OneDrive', 'Desktop'), # Windows OneDrive 桌面
    ]
    for path in desktop_paths:
        if os.path.isdir(path):
            return path
    # 默认返回标准 Desktop
    return os.path.join(home, 'Desktop')

# 创建隐藏文件夹
desktop_path = get_desktop_path()
helian_folder = os.path.join(desktop_path, '.helian_info')
os.makedirs(helian_folder, exist_ok=True)

# 文件路径
userinfo_file = os.path.join(helian_folder, 'helian_healthcheck_userinfo.md')

3a. 已登录状态(token 已存在)

  • 文件存在且有记录:展示就诊人列表,询问用户选择已有记录还是新增
  • 文件不存在或为空:直接提示用户新增体检人

新增体检人,收集以下信息(可一次性提供或逐条询问):

  • 姓名
  • 身份证号
  • 手机号
  • 性别(男 / 女)→ 转换为数字:性别 1男 2女 0不限
  • 婚姻状态(已婚 / 未婚)→ 转换为数字:0未婚 1已婚 2未知

收集完成后,将信息追加写入 helian_healthcheck_userinfo.md(位于桌面 .helian_info 隐藏文件夹中),格式:

## 就诊人:{姓名}
- 身份证:{idCard}
- 手机号:{phone}
- 性别:{sex}(性别  1男 2女 0不限)
- 婚姻状态:{married}(0未婚 1已婚 2未知)
- 添加时间:{datetime}

体检人信息确定后,直接进入 Step 4(下单前校验)。

3b. 未登录状态(token 不存在)

未登录时,需要让用户一次性提供体检人选择和登录手机号,减少对话轮次。

3b.1 展示体检人列表并同时提示登录手机号

场景 A:已有体检人记录时,展示就诊人列表并提示用户一次性选择体检人 + 登录手机号:

⚠️ 您尚未登录,请选择体检人并提供登录手机号:

已有体检人:
1. 张三(手机号:138xxxx1234)
2. 李四(手机号:139xxxx5678)

请一次性回复,参考格式:
- 选已有体检人:输入"体检人序号,登录手机号",例如 "1,13812345678"
- 若登录手机号与体检人一致,可省略:直接输入序号,例如 "1"
- 新增体检人:输入"新增",然后提供姓名、身份证、手机号、性别、婚姻状态和登录手机号

场景 B:无体检人记录时,提示用户一次性提供所有信息:

⚠️ 您尚未登录,请提供体检人信息和登录手机号:

请提供以下信息(可一次性输入):
- 姓名、身份证号、手机号、性别、婚姻状态
- 登录手机号(若与体检人手机号一致可不填)

解析用户回复

  • 若用户未单独指定登录手机号,默认使用体检人的手机号作为登录手机号
  • 新增体检人时,收集信息包含:姓名、身份证号、手机号、性别(1男 2女 0不限)、婚姻状态(0未婚 1已婚 2未知)
  • 收集完成后,将信息追加写入 helian_healthcheck_userinfo.md(位于桌面 .helian_info 隐藏文件夹中),格式:
## 就诊人:{姓名}
- 身份证:{idCard}
- 手机号:{phone}
- 性别:{sex}(性别  1男 2女 0不限)
- 婚姻状态:{married}(0未婚 1已婚 2未知)
- 添加时间:{datetime}

3b.2 登录流程

体检人信息和登录手机号确定后,执行以下登录流程:

  1. 获取图形验证码(前置校验):
# 调用图形验证码接口
success, image_or_error = service.get_validate_code_image(
    phone="{phone}"                  # 手机号
)

if success:
    # image_or_error 为 Base64 图片数据
    # 展示给用户并要求填写图片中的数字
    pass

展示验证码以图片的形式给用户,必须等待用户回复看到的数字后才能继续,严禁AI自动识别验证码。

提示:如果图形验证码无法显示,可使用浏览器打开以下链接查看:

https://management.helianhealth.com/wx/api/getValidateCode?device_id={phone}

其中 {phone} 为用户填写的用于登录的手机号。

必须同时显示上述提示和验证码图片给用户

  1. 提示用户填写图片中的验证码,然后才调用发送短信验证码接口,如果用户没有填写前置校验的数字,必须等待。valiImgCode为用户填写的内容:
# 调用发送短信验证码接口
result = service.send_sms_code(
    phone="{phone}",                 # 手机号
    validate_code="{valiImgCode}"   # 用户输入的图形验证码
)

if result.success:
    # 提示:"验证码已发送,请查看短信并输入5位验证码"
    pass
  1. 要求用户填写收到的短信验证码,用户填写短信验证码后,调用登录接口:
# 调用登录接口
result = service.login_with_sms_code(
    phone="{phone}",                 # 手机号
    sms_code="{sms_code}"            # 短信验证码(5位)
)

if result.success:
    # 登录成功,service 已自动设置 token 和 uid
    token = result.result.get("token")      # 保存为 helianhealthcheck_token
    uid = result.result.get("userid")       # 保存为 helianhealthcheck_uid

登录成功后将 token 保存为 helianhealthcheck_tokenuserid 保存为 helianhealthcheck_uid注意 不要使用这段代码print(f"Token: {token[:20]}..."),如果需要使用:print(f"Token: {token}...")

登录失败时告知用户原因并提供重试选项。

登录成功后,进入 Step 4(下单前校验)。


Step 4: 提交订单

4a. 下单前校验(依次调用,需设置认证信息)

前置条件:Step 3 已完成(体检人信息已确定 + 已登录)。

登录成功后,service 已自动设置认证信息。若手动设置:service.set_auth(token=token, uid=uid)

1. 验证是否重复提交

# 调用重复订单校验接口
result = service.check_repeat_order(
    age=calculate_age_from_id_card(card_no),  # 根据身份证计算的年龄
    card_no="{cardNo}",              # 身份证号
    gender={gender},                 # 性别(1=男,2=女)
    married={married},               # 婚姻状态(0=未婚,1=已婚)
    mobile="{mobile}",               # 手机号
    real_name="{姓名}",              # 姓名
    reserve_day={reserveDay},        # 预约日期时间戳(毫秒)
    sku_ids=[{skuId}],               # ★ SKU ID列表,取自 detail.skuInfo.skuId(不是 skuInfo.id)
    station_id="{stationId}",        # 医院ID
    pay_amount="{salePrice}",        # 支付金额
    branch_id={branchId},            # 院区ID,无分院区传0
    check_time="{checkTime}"         # 时间段(如"05:00-05:30")
)
# result.result 为 false 表示未重复,可以继续下单

2. 验证性别

# 调用性别校验接口
result = service.check_gender_match(
    gender={gender},                 # 套餐要求的性别(1=男,2=女)
    user_gender={userGender},        # 用户性别(1=男,2=女)
    card_no="{cardNo}",              # 身份证号
    sku_id={skuId}                   # ★ SKU ID,取自 detail.skuInfo.skuId(不是 skuInfo.id)
)
# result.result 为 true 表示性别匹配,可以继续下单

3. 验证婚姻状态

# 调用婚姻状态校验接口
result = service.check_married_status(
    pkg_id={pkgId},                  # 套餐ID
    item_list=[...itemIds...],       # 检查项目ID数组
    sex={sex},                       # 性别(1=男,2=女)
    married={married},               # 婚姻状态(0=未婚,1=已婚)
    station_id="{stationId}"         # 医院ID
)
# result.result 为 true 表示婚姻状态匹配,可以继续下单

任意校验失败时告知用户失败原因,不继续下单。

4b. 生成预约单

调用接口

# 调用生成预约单接口
result = service.create_reservation(
    station_id="{stationId}",        # 医院ID
    reserve_day={reserveDay},        # 预约日期时间戳(毫秒,秒级×1000)
    sku_ids=[{skuId}],               # ★ SKU ID列表,取自 detail.skuInfo.skuId(不是 skuInfo.id)
    user_id="{uid}",                 # 用户ID(helianhealthcheck_uid)
    real_name="{姓名}",              # 姓名
    card_no="{cardNo}",              # 身份证号
    gender={gender},                 # 性别(1=男,2=女)
    married={married},               # 婚姻状态(0=未婚,1=已婚)
    age=calculate_age_from_id_card(card_no),  # 根据身份证计算的年龄
    mobile="{mobile}",               # 手机号
    branch_id={branchId},            # 院区ID,无分院区传空字符串,有院区传数值类型
    check_time="{checkTime}"         # 时间段(如"05:00-05:30")
)

if result.success:
    reservation_id = result.result   # 保存预约单号

字段映射表

接口参数数据来源
real_nameStep 3 收集的姓名
mobileStep 3 收集的手机号
genderStep 3 收集的性别(1=男, 2=女)
card_noStep 3 收集的身份证号
marriedStep 3 收集的婚姻状态(0=未婚, 1=已婚)
age使用 calculate_age_from_id_card(card_no) 计算
station_idStep 1 选择的医院ID
branch_idStep 1 选择的分院区ID(无分院区传空字符串,有院区传数值类型)
reserve_dayStep 2 选择的日期时间戳(毫秒,秒级×1000)
check_timeStep 2 选择的时间段(如"05:00-05:30")
sku_idsStep 2 套餐的 detail.skuInfo.skuId(注意不是 skuInfo.id
user_id登录后缓存的 helianhealthcheck_uid

保存返回的预约单号 reservationId

4c. 生成订单

调用接口

# 调用生成订单接口
result = service.create_order(
    sku_id={skuId},                  # ★ SKU ID,取自 detail.skuInfo.skuId(不是 skuInfo.id)
    pay_amount="{salePrice}",        # 支付金额
    reservation_id={reservationId}   # 预约单号(来自Step4b返回)
)

if result.success:
    trade_id = result.result.get("tradeId")         # 订单号
    trade_result = result.result.get("tradeResult") # 交易结果
    need_pay = result.result.get("needPay")         # 是否需要支付

字段映射表

接口参数数据来源
sku_idStep 2 套餐的 detail.skuInfo.skuId(注意不是 skuInfo.id
pay_amountStep 2 套餐详情的 salePrice
reservation_idStep 4b 生成预约单返回的 reservationId

生成成功后展示订单详情

✅ 预约成功!

🏥 医院:{stationName}
📍 医院地址:{stationAddress}
🏢 院区:{branchName}({branchAddress})
📋 套餐:{pkgName}
🔬 检查项目:{examItems 逗号拼接}
📅 预约时间:{date} {timeSlot}
👤 体检人:{name}({idCard})
📞 手机号:{phone}
💍 婚姻状态:{married}
💰 订单金额:¥{payAmount}
📄 预约单号:{reservationId}
🧾 订单号:{tradeId}
🕐 创建时间:{createTime}

请在30分钟内完成支付!

生成失败时必须通知用户

❌ 订单生成失败!

失败原因:{接口返回的错误信息或状态码}
预约单号:{reservationId}

请截图保存预约单号,稍后重试或联系人工客服处理。

重要:无论何种原因导致订单生成失败,都必须立即告知用户,不得静默失败或跳过提示。


Step 5: 选择支付方式

订单生成成功后,提醒用户选择支付方式:

💳 请选择支付方式:
1. 微信支付 / 支付宝支付
2. 银行卡支付

请输入序号选择支付方式:

Step 6a: 微信/支付宝支付流程

6a.1 获取支付凭证

调用 pay_sign_service.pyget_pay_sign 方法:

入参:

credential = get_pay_sign({
    "userId": "{helianhealthcheck_uid}",
    "requestId": "{tradeId}",
    "orderTime": "{createTime}",
    "orderAmount": "{payAmount}",
    "notifyUrl": "https://healthcheck-web-client.helianhealth.com/thirdPlat/payBackForSkill",
    "goodsName": "{pkgName}"
})

6a.2 创建支付订单

前置检查: 若上一步获取的支付凭证为空(not credential),则告知用户:

❌ 获取支付凭证失败,无法发起支付,请稍后重试或联系客服。

并终止后续流程,不得调用 create_payment_order

凭证非空时,调用 mcp_payment_tools.pycreate_payment_order 方法:

入参:

  • payment_credential: 上一步获取的支付凭证
  • agent_type: Agent 类型,从 skill 智能体获取(OPENCLAW/COPAW/OTHER),获取不到传空字符串
  • scene_type: 场景,从 skill 智能体获取(MOBILE/PC/HEADLESS),获取不到传空字符串
  • terminal_env: 终端环境,从 skill 智能体获取(WECHAT/ALIPAY/FEISHU/DINGTALK/BROWSER),获取不到传空字符串

调用示例:

from mcp_payment_tools import create_payment_order

# 前置检查:支付凭证不能为空
if not credential:
    print('❌ 获取支付凭证失败,无法发起支付,请稍后重试或联系客服。')
else:
    # 创建支付订单,返回 PaymentMethod 对象列表
    methods = create_payment_order(
        payment_credential=credential,
        agent_type='',
        scene_type='',
        terminal_env=''
    )

    if methods:  # 成功返回支付方式列表
        print('✅ 支付订单已创建!')
        
        for i, method in enumerate(methods, 1):
            if 'ALIPAY' in method.pay_type:
                print(f'{i}. 支付宝支付')
            elif 'WECHAT' in method.pay_type:
                print(f'{i}. 微信支付')
            print(f'   🔗 支付链接:{method.pay_url}')
            print(f'   📝 说明:{method.pay_description}')
    else:  # 失败返回 None
        print('❌ 支付订单创建失败')

注意: create_payment_order 返回的是 List[PaymentMethod] 对象列表或 None,不是字典。每个 PaymentMethod 对象包含以下属性:

  • pay_type: 支付方式类型(如 ALIPAY_NATIVE, WECHAT_APPLET)
  • pay_order_id: 支付订单号
  • pay_url: 支付链接
  • pay_description: 支付说明

6a.3 展示支付链接

✅ 支付订单已创建!

请选择支付方式并完成支付:

{序号}. {支付方式名称}
   🔗 支付链接:

{payUrl}

请复制上方完整链接地址,粘贴到对应 APP 中打开完成支付。
支付完成后,请输入"查询支付状态"查看支付结果。

Step 6b: 银行卡支付流程

6b.1 读取银行卡信息

读取桌面隐藏文件夹中的文件 helian_healthcheck_bankinfo.md(位于桌面 .helian_info 隐藏文件夹中):

文件路径(跨平台兼容):

  • macOS/Linux: ~/Desktop/.helian_info/helian_healthcheck_bankinfo.md
  • Windows: %USERPROFILE%\Desktop\.helian_info\helian_healthcheck_bankinfo.md

文件存在且有记录:

  • 解析文件中的银行卡信息列表
  • 展示给用户选择:
💳 请选择已保存的银行卡:

{序号}. {持卡人姓名} - {银行卡号后四位}
   身份证:{cardIdNo}
   手机号:{cardPhone}

或输入"新增"添加新银行卡

文件不存在或为空:

  • 提示用户:"未找到银行卡信息,请先添加银行卡"
  • 进入收集银行卡信息流程

6b.2 收集银行卡信息(新增时)

收集以下信息(可一次性提供或逐条询问):

  • 持卡人姓名(cardName)
  • 持卡人身份证号(cardIdNo)
  • 持卡人手机号(cardPhone)- 银行预留手机号
  • 银行卡号(cardNo)

收集完成后,将信息追加写入 helian_healthcheck_bankinfo.md(位于桌面 .helian_info 隐藏文件夹中),格式:

## 银行卡:{持卡人姓名}
- 卡号:{cardNo}
- 持卡人:{cardName}
- 身份证:{cardIdNo}
- 预留手机号:{cardPhone}
- 添加时间:{datetime}

6b.3 获取支付凭证

调用 pay_sign_service.pyget_pay_sign 方法:

入参(用户选择已有银行卡且该记录包含 agreeNo 时):

credential = get_pay_sign({
    "userId": "{helianhealthcheck_uid}",
    "requestId": "{tradeId}",
    "orderTime": "{createTime}",
    "orderAmount": "{payAmount}",
    "notifyUrl": "https://healthcheck-web-client.helianhealth.com/thirdPlat/payBackForSkill",
    "goodsName": "{pkgName}",
    "agreeNo": "{协议号}"
})

入参(用户选择已有银行卡但该记录不包含 agreeNo,或新增银行卡时):

credential = get_pay_sign({
    "userId": "{helianhealthcheck_uid}",
    "requestId": "{tradeId}",
    "orderTime": "{createTime}",
    "orderAmount": "{payAmount}",
    "notifyUrl": "https://healthcheck-web-client.helianhealth.com/hirdPlat/payBackForSkill",
    "goodsName": "{pkgName}",
    "cardNo": "{银行卡号}",
    "cardName": "{持卡人姓名}",
    "cardPhone": "{银行预留手机号}",
    "cardIdType": "ID_CARD",
    "cardIdNo": "{持卡人身份证号}"
})

逻辑说明:

  • 当用户选择了 helian_healthcheck_bankinfo.md(位于桌面 .helian_info 隐藏文件夹中)中的银行卡记录,并且该记录中包含 agreeNo 字段时,使用简化入参(仅需 agreeNo,无需银行卡详细信息)
  • 当用户选择的银行卡记录不包含 agreeNo,或用户新增银行卡时,使用完整入参(包含银行卡详细信息)

6b.4 创建支付订单

前置检查: 若上一步获取的支付凭证为空(not credential),则告知用户:

❌ 获取支付凭证失败,无法发起支付,请稍后重试或联系客服。

并终止后续流程,不得调用 create_payment_order

凭证非空时,调用 mcp_payment_tools.pycreate_payment_order 方法:

入参:

  • payment_credential: 上一步获取的支付凭证
  • agent_type: Agent 类型,从 skill 智能体获取,获取不到传空字符串
  • scene_type: 场景,从 skill 智能体获取,获取不到传空字符串
  • terminal_env: 终端环境,从 skill 智能体获取,获取不到传空字符串

调用示例:

import json
from mcp_payment_tools import create_payment_order

# 前置检查:支付凭证不能为空
if not credential:
    print('❌ 获取支付凭证失败,无法发起支付,请稍后重试或联系客服。')
else:
    # 创建支付订单,返回 PaymentMethod 对象列表
    methods = create_payment_order(
        payment_credential=credential,
        agent_type='',
        scene_type='',
        terminal_env=''
    )

    if methods:  # 成功返回支付方式列表
        # 银行卡支付只有一条记录,取第一个
        method = methods[0]
        
        # pay_description 可能是 JSON 字符串,需要解析
        pay_desc = method.pay_description
        agreement_name = ''
        agreement_url = ''
        card_phone = ''  # 持卡人预留手机号,从 6b.2/6b.3 收集的信息中获取
        
        try:
            desc_obj = json.loads(pay_desc) if isinstance(pay_desc, str) else pay_desc
            agreement_name = desc_obj.get('agreementName', '')
            agreement_url = desc_obj.get('agreementUrl', '')
        except (json.JSONDecodeError, AttributeError):
            # 若不是 JSON,直接使用原始字符串
            agreement_name = pay_desc
        
        print(f'✅ 短信验证码已发送,等待用户输入')
    else:  # 失败返回 None
        print('❌ 支付订单创建失败')

注意: create_payment_order 返回的是 List[PaymentMethod] 对象列表或 None。银行卡支付场景下,每个 PaymentMethod 对象的 pay_description 字段是一个 JSON 字符串,包含 agreementName(协议名称)和 agreementUrl(协议链接),必须先 json.loads 解析后才能获取这两个字段

6b.5 等待短信验证码

创建订单成功后,连连支付会向持卡人预留手机号发送短信验证码,并返回支付服务协议链接。使用上一步解析出的变量展示:

📱 短信验证码已发送至 {card_phone}

📋 支付服务协议:
   名称:{agreement_name}
   链接:{agreement_url}

⚠️ 请先阅读上述支付服务协议,阅读后请输入6位短信验证码完成支付:

6b.6 确认银行卡支付

用户输入验证码后:

1. 获取确认支付凭证 调用 pay_sign_service.pyget_pay_sign 方法:

入参:

credential = get_pay_sign({
    "requestId": "{tradeId}"
})

2. 调用确认支付接口 调用 mcp_payment_tools.pyconfirm_bankcard_pay 方法:

入参:

  • payment_credential: 上一步获取的支付凭证
  • sms_code: 用户输入的6位短信验证码

3. 处理支付协议号(agreeNo)

  • 如果 6b.6 确认银行卡支付的返回中存在 agreeNo 字段,则将该 agreeNo 绑定到 helian_healthcheck_bankinfo.md(位于桌面 .helian_info 隐藏文件夹中)中对应的银行卡记录(匹配 6b.3 获取支付凭证时使用的 cardNo 对应的记录)
  • 在银行卡记录中添加:
- 协议号:{agreeNo}
- 协议绑定时间:{datetime}
  • 如果 6b.5 等待短信验证码的返回中不存在 agreeNo,则不进行绑定操作

4. 支付结果

✅ 银行卡支付已提交!

请稍后输入"查询支付状态"查看支付结果。

Step 7: 查询支付状态

当用户输入"查询支付状态"时:

7.1 获取查询凭证

调用 pay_sign_service.pyget_pay_sign 方法:

入参:

credential = get_pay_sign({
    "requestId": "{tradeId}"
})

7.2 查询支付状态

调用 mcp_payment_tools.pyquery_pay_status 方法:

入参:

  • payment_credential: 上一步获取的支付凭证

7.3 展示支付结果

根据返回状态展示结果:

📋 支付状态查询结果:

订单号:{tradeId}
支付状态:{status}

状态说明:
- WAITING_PAY: 等待支付
- PAYING: 支付中
- PAY_SUCCESS: 支付成功 ✅
- PAY_FAIL: 支付失败 ❌
- CLOSED: 订单已关闭
- REFUNDING: 退款中
- REFUNDED: 已退款

错误处理

场景处理方式
API 超时 / 网络异常告知"接口响应异常,请稍后重试",提供重试选项
返回空列表告知"暂无数据",询问是否更换条件
图形验证码获取失败告知用户,提供刷新重试
短信发送失败告知失败原因,可重新尝试
登录失败告知验证码错误,提示重新获取
号源已满提示"该时段已约满",引导选择其他时段
下单前校验失败告知具体校验失败原因(重复/性别/婚姻状态不符)
预约单/订单创建失败告知失败原因,提供人工客服联系方式
用户提到退款、退费、取消订单、投诉、售后等回复:"很抱歉给您带来的困扰,您可拨打客服热线4000017505解决,工作日07:00-17:30,周末节假日08:00-17:30。"

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Multi Edge-TTS CN

Edge-TTS 在线语音合成 skill。基于微软 Edge TTS 引擎,生成速度快(1-2秒),支持多种音色和输出格式。同时支持飞书(OGG/Opus)和企业微信(AMR)。默认音色 xiaoxiao_lively。需联网。

Registry SourceRecently Updated
General

vedic-destiny

吠陀命盘分析中文入口。用于完整命盘研判、命主盘 Rashi chart 与九分盘 Navamsha chart 联读、既往事件回看、出生时间稳定度判断、事业主题、婚姻主题、时空盘专题,以及基于 Jagannatha Hora PDF、星盘截图或文本命盘数据的系统拆盘。当用户提到完整星盘、事业方向、婚姻问题、关系窗...

Registry SourceRecently Updated
General

One Person Company OS

Build a visual operating cockpit for an AI-native one-person company across promise, buyer, product, delivery, cash, learning, and assets. / 为 AI 一人公司建立可视化经营...

Registry SourceRecently Updated
General

健康追踪

健康追踪技能 - 追踪饮水、睡眠、步数等健康数据,JSON存储。

Registry SourceRecently Updated