Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component...
npx skills add jianhao3776/skill-hub --skill "meeting-room-booking"
Install specific skill from multi-skill repository
# Description
美团会议室预订助手,在 https://calendar.sankuai.com/rooms 进行会议室查询与预定的浏览器自动化流程。用户提出订会议室、预约会议室、找会议室、安排会议地点、确认某时段是否有空会议室、预定会议室时使用。支持 SSO 扫码登录、按日期时间人数地点筛选、时间轴空白块点击创建、提交前确认与结果核验。
# SKILL.md
name: meeting-room-booking
description: 美团会议室预订助手,在 https://calendar.sankuai.com/rooms 进行会议室查询与预定的浏览器自动化流程。用户提出订会议室、预约会议室、找会议室、安排会议地点、确认某时段是否有空会议室、预定会议室时使用。支持 SSO 扫码登录、按日期时间人数地点筛选、时间轴空白块点击创建、提交前确认与结果核验。
icon: assets/icon.png
美团会议室预订助手
快速开始
会议室预订流程分为四步:
- SSO 登录获取 Cookie:通过 browser use 自动化完成扫码登录,获取 Cookie
- 收集预订信息:城市、大厦、楼层、日期、时间段、人数
- 查询空闲会议室:通过 API 检索符合的会议室和其预订状态
- 提交预订:找到空闲会议室后通过 API 自动提交
使用示例
- ✅ "帮我订一个北京保利广场西座明天上午10-11点的会议室,5个人"
- ✅ "查一下上海互联D2栋下午14-15点有没有空会议室"
- ✅ "我需要一个容纳15人的会议室,成都科技园,后天下午"
美团内网 SSO 登录与 Cookie 获取
所有美团内部网站(*.sankuai.com)共享同一套 SSO 登录机制。必须先通过 browser use 完成登录并获取 Cookie,后续查询与预订全部通过 API 调用完成。
判断是否需要登录
以下任一条件成立即表示未登录,需要走 SSO 流程:
- URL 包含
ssosv、sso.sankuai.com、passport.sankuai.com - 页面出现二维码扫码界面
- 页面无目标站点的核心业务元素(如会议室页面的时间轴、会议室列表)
SSO 扫码登录流程
- 通过 browser use 打开
https://calendar.sankuai.com/rooms。 - 保持登录页可见,等待二维码加载完成。
- 明确提示用户:"请使用手机扫码登录"。
- 轮询页面状态(间隔 2-3 秒);检测到 URL 不再包含 SSO 关键词且出现目标站点业务元素后继续。
- 若等待超时(>60s)或二维码失效,刷新页面并提示用户重试。
禁止:不要要求用户提供账号密码或验证码,仅支持扫码登录。
若登录后仍无法进入会议室列表,立即告知失败原因并询问是否改为仅做信息整理(不提交)。
登录后获取 Cookie
SSO 登录成功后,立即通过 browser use 在页面内执行 JS 获取 Cookie:
document.cookie
将获取到的 Cookie 字符串保存到会话中,后续所有 API 调用都携带此 Cookie。
重要:仅 SSO 登录环节使用 browser use 自动化操作;查询与预订全部通过 API 调用完成,禁止用 browser use 操作会议室列表页面。
信息收集流程
收集策略
依序收集以下信息(每次只问一个问题):
| 参数 | 是否必填 | 说明 | 示例 |
|---|---|---|---|
| 城市 | 必填 | 用户输入城市名称 | 北京、上海、成都 |
| 园区/大楼 | 必填 | 从下拉列表中选择 | 北京/保利广场西座 |
| 楼层 | 可选 | 不指定则标记为"不限楼层" | 2层、3层 |
| 日期 | 必填 | 具体日期 | 2026-02-18 |
| 时间段 | 必填 | 开始和结束时间 | 10:00-12:00 |
| 人数 | 可选 | 默认5人 | 5、10、15 |
默认值策略
用户未指定时,应用以下默认值并提示用户确认:
- 日期:今天
- 开始时间:当前时间 + 2小时,向上取整到最近半点
- 时长:60分钟
- 人数:5人
- 楼层:不限楼层
预订规则(必须遵守)
在收集信息阶段即校验以下规则,不符合时立即告知用户:
1. 预订窗口限制
- 每日 9:30 开放未来 8 个自然日内的预订权限
- ❌ 超过 8 天 → 提示不可预订,建议调整日期
2. 次数限制
- 同一账号每天每间会议室最多可预订 3 次
3. 时长限制
- 单次会议可预订时长:15 分钟 ~ 240 分钟(4 小时)
- ❌ 超出范围 → 建议拆分或调整
4. 历史时间不可预订
- 当前时间以前的时间段不可预订
- ❌ 早于当前时间 → 立即提示并要求重新填写
5. 查询时间范围限制
- API 仅支持查询历史 7 天内的会议室数据
- 超过 7 天的请求会返回
"仅支持历史7天内的数据查询"错误 - 对于超过 7 天的预订,需要提示用户调整日期范围
空闲会议室查询流程
步骤 1:获取城市、大厦和楼层列表
调用接口:POST https://calendar.sankuai.com/meeting/api/pc/room/appointment/findCityBuildingAndFloor
请求头:必须携带浏览器当前 Cookie 保持登录状态
返回数据示例:
{
"code": 200,
"message": "success",
"data": [
{
"cityId": 3531,
"cityName": "北京市",
"buildingAndFloorVoList": [
{
"building": {
"id": 843,
"name": "北京/保利广场西座"
},
"floors": [
{
"id": 2001,
"name": "2层"
},
{
"id": 2002,
"name": "3层"
}
]
}
]
}
]
}
从返回结果中提取用户选择的城市、大厦、楼层对应的 ID。
步骤 2:查询其他条件列表
调用接口:GET https://calendar.sankuai.com/room/front/pc/room/moreInfo
返回结构包含:
- equips:可用设备列表(Zoom、腾讯会议、投影等)
- capacity:容量范围选项(1-6人、7-14人、15-21人等)
- window:窗户选项(有窗/无窗)
根据用户的人数需求,选择对应的容量范围。
步骤 3:筛选可用会议室
调用接口:POST https://calendar.sankuai.com/meeting/api/pc/room/appointment/v2/find-rooms
请求体参数:
{
"date": 1772553600000,
"buildingId": "843",
"floorIds": [],
"capacity": [{"capacityMin": 7, "capacityMax": 14, "name": "7-14人"}],
"startTime": "10:00",
"endTime": "18:00"
}
| 参数 | 说明 |
|---|---|
date |
查询日期的时间戳(毫秒,必须在 7 天内) |
buildingId |
大楼 ID(字符串) |
floorIds |
楼层 ID 数组,空数组表示不限楼层 |
capacity |
容量范围对象数组 |
startTime/endTime |
时间范围(HH:MM 格式) |
返回数据包含:会议室 ID、名称、容量、楼层、设备、邮箱、地址等信息。
步骤 4:查询会议室预订情况
调用接口:POST https://calendar.sankuai.com/meeting/api/pc/room/appointment/findRoomAppointmentsV2
请求体参数:
{
"date": 1772553600000,
"roomIds": [11525, 11516, 11591]
}
返回数据示例:
{
"code": 200,
"message": "success",
"data": [
{
"roomId": 11516,
"appointmentVOS": [
{
"id": "54986818",
"title": "郝妍的会议",
"startTime": 1772593200000,
"endTime": 1772596800000,
"isRecur": false
}
]
}
]
}
分析返回结果,找出用户指定时间段内没有预订记录的会议室。
会议室预订提交
找到空闲会议室后,直接提交预订,无需等待用户额外确认。
提交接口
调用接口:POST https://calendar.sankuai.com/api/v2/xm/schedules
请求体(完整参数格式):
{
"title": "会议主题",
"startTime": 1772848800000,
"endTime": 1772852400000,
"isAllDay": 0,
"location": "",
"attendees": ["6485487"],
"noticeType": 0,
"noticeRule": "P0Y0M0DT0H10M0S",
"recurrencePattern": {
"type": "NONE",
"showType": "NONE"
},
"deadline": 0,
"memo": "",
"organizer": "6485487",
"room": {
"id": 11486,
"name": "富春厅",
"email": "[email protected]",
"capacity": 13,
"floorId": 2001,
"floorName": "2层",
"buildingId": 843,
"buildingName": "北京/保利广场西座"
},
"appKey": "meeting",
"bookType": 11
}
必填字段说明:
| 字段 | 类型 | 说明 | 必填 |
|---|---|---|---|
| title | string | 会议标题 | 是 |
| startTime | number | 开始时间(毫秒时间戳) | 是 |
| endTime | number | 结束时间(毫秒时间戳) | 是 |
| isAllDay | number | 是否全天(0=否) | 是 |
| organizer | string | 组织者 ID(用户 MIS 账号对应的数字 ID,见下方"获取 organizer ID") | 是 |
| attendees | array | 参与人员 ID 列表 | 是 |
| room | object | 会议室信息(需包含 id, name, email, capacity, floorId, floorName, buildingId, buildingName) | 是 |
| appKey | string | 应用标识(固定为"meeting") | 是 |
| bookType | number | 预订类型(固定为11) | 是 |
| noticeType | number | 通知类型(固定为0) | 否 |
| recurrencePattern | object | 循环模式(固定为 {type:"NONE",showType:"NONE"}) | 否 |
| deadline | number | 截止时间(固定为0) | 否 |
| memo | string | 备忘录(留空) | 否 |
| location | string | 位置描述(留空) | 否 |
📋 获取 organizer ID
organizer 字段需要填写用户的员工 ID(empId),而不是 MIS 账号。可以通过以下接口查询:
接口:查询员工信息
curl 'https://calendar.sankuai.com/api/v2/xm/meeting/dataset/account' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/plain, */*' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'M-UserContext: eyJsb2NhbGUiOiJ6aCIsInRpbWVab25lIjoiQXNpYS9TaGFuZ2hhaSJ9' \
-H 'Cookie: [你的Cookie]' \
--data-raw '{"filter":"[员工MIS账号]"}'
请求参数:
- filter: 员工的 MIS 账号(如:wb_yuanfangsheng)
返回示例:
{
"data": [
{
"name": "袁芳胜",
"empId": "22244841",
"mis": "wb_yuanfangsheng",
"email": "...",
"avatar": "..."
}
],
"code": 200,
"message": "success"
}
提取 empId 并用于 organizer 字段。
自动化说明:
- 当你提供 Cookie 后,我会自动调用此接口查询你的 empId
- 后续预订时自动使用该 ID,无需手动查询
⚠️ 时间戳计算方法
使用精确的 Unix 毫秒时间戳(注意不能使用错误的计算方式):
from datetime import datetime, timezone, timedelta
# 正确方式:使用 timezone 对象
dt = datetime(2026, 3, 7, 10, 0, 0, tzinfo=timezone(timedelta(hours=8)))
timestamp_ms = int(dt.timestamp() * 1000)
提交后处理
成功标志:
- API 返回 "message":"成功"
- 或返回 redirectUrl 字段
- HTTP 状态码 200
成功反馈(包含以下信息):
- ✅ 会议室名称
- ✅ 日期和时间段
- ✅ 地点(城市/大楼/楼层)
- ✅ 容量
失败处理:
| 失败原因 | 错误信息 | 处理建议 |
|---|---|---|
| 时间参数格式错误 | "时间参数不合法" | 检查时间戳是否正确(使用毫秒级时间戳) |
| 预订过去时间 | "过去时间不可预订会议室" | 提示用户选择未来时间 |
| 会议室已被预订 | "会议室已被预订,请重新选择" | 选择其他会议室或改时间 |
| 查询超过7天 | "仅支持历史7天内的数据查询" | 提示用户只能预订7天内的会议室 |
| 登录失效 | "未登录" | 提示用户重新登录并更新 Cookie |
| 权限不匹配 | "权限不匹配,拒绝操作" | 检查 organizer 和 attendees 是否有效 |
常见问题处理
Q: 用户说"明天上午",如何处理?
A: 将"明天"转换为具体日期,"上午"默认为 10:00-11:00,询问用户确认。
Q: 用户要求"4小时会议"但超出时长限制?
A: 提示单次最多 4 小时,建议分成两次预订或调整时长。
Q: 没有找到空闲会议室?
A: 返回所有候选会议室及其被占用时段,建议用户调整时间或选择其他地点。
Q: 用户只想查询可用性,不想预订?
A: 禁止提交,仅输出可用会议室列表。
Q: 如何获取有效的 Cookie?
A: 系统会自动通过 browser use 打开会议室页面并引导你扫码登录。登录成功后自动通过 document.cookie 提取 Cookie,全程无需手动操作。
Q: 整个预订过程需要用户手动做什么吗?
A: 只需要在首次登录时用手机扫码,其余全部自动完成。
Q: 如何获取 organizer ID(员工 ID)?
A:
自动方式(推荐):
告诉我你的 MIS 账号(如:wb_yuanfangsheng),我会:
- 自动调用员工信息查询接口
- 提取你的 empId
- 后续预订时自动使用
手动方式:
执行以下 curl 命令:
curl 'https://calendar.sankuai.com/api/v2/xm/meeting/dataset/account' \
-H 'Content-Type: application/json' \
-H 'Cookie: [你的Cookie]' \
--data-raw '{"filter":"[你的MIS账号]"}'
返回结果中的 empId 字段就是 organizer ID。
示例:
- 输入 MIS 账号:wb_yuanfangsheng
- 返回 empId:22244841 ← 这个就是 organizer ID
Q: Cookie 过期了怎么办?
A: 系统会检测到 API 返回"未登录"错误,自动重新通过 browser use 打开会议室页面引导你扫码登录,获取新的 Cookie 后继续操作。
Q: organizer 和 attendees 的区别?
A:
- organizer:会议组织者(发起人),必须是你自己的 empId
- attendees:参会人员列表(可包括多个人),数组格式,通常至少包含组织者本人
例如:
{
"organizer": "22244841",
"attendees": ["22244841"]
}
关键提示
🤖 自动化能力
- SSO 登录自动化:通过 browser use 引导扫码登录,自动提取 Cookie
- API 调用自动化:查询与预订全部通过 API 完成,无需操作页面
- 参数处理自动化:自动计算时间戳、构建请求体、解析响应
- 流程自动化:从登录到预订的全流程一键执行
⚙️ 技术细节
- Cookie 管理:SSO 登录后自动通过
document.cookie获取,过期时自动重新登录 - 时间戳转换:自动转换为毫秒级 Unix 时间戳(北京时间 UTC+8)
- 查询限制:自动检查 7 天范围限制,提示用户调整
- 完整参数:自动补全所有必填参数,确保请求成功
📱 用户体验
- 仅需扫码:首次登录扫码后全程自动
- 智能纠正:对无效输入自动提示和纠正
- 失败重试:遇到临时失败自动重试或建议替代方案
- 进度反馈:实时显示各步骤进度
执行流程优化建议
基于实际使用经验,预订流程已优化为以下步骤:
步骤 1:信息收集
- ✅ 从自然语言中提取关键信息(城市、建筑、日期、时间、人数)
- ✅ 校验预订时间合法性
- ✅ 自动填充缺失的默认值
步骤 2:快速查询
- ✅ 一次性调用 API 获取城市、建筑、楼层列表
- ✅ 从建筑列表中模糊匹配用户指定的建筑
- ✅ 根据人数需求确定容量范围
步骤 3:房间筛选
- ✅ 调用一次接口查询所有符合条件的房间(避免多次查询)
- ✅ 批量查询这些房间的预订情况(单次请求包含多个房间 ID)
- ✅ 在内存中过滤出无冲突的空闲房间
步骤 4:自动预订
- ✅ 选择第一个空闲房间或按人数/楼层偏好选择
- ✅ 自动获取用户 empId(基于 MIS 账号)
- ✅ 直接提交预订,无需等待用户确认
步骤 5:结果确认
- ✅ 展示预订成功的完整信息
- ✅ 提供可用房间列表作为备选方案
详细参考资源
- 完整的 API 参数详细说明,见 reference.md
- 实际使用示例和对话案例,见 examples.md
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.