最近做的企微二开,员工反馈操作太繁琐——查客户要进 CRM、建工单要进工单系统。业务方要求在企微里用"快捷指令":输入"/查客户 张三"直接返回客户信息。快捷指令的本质是把企微消息接口和业务接口串起来——员工发一条消息,后端解析指令、调对应接口、把结果用消息发回去。把每个指令调了哪些接口记下来。
底层用的是Eyun 平台开放的企微 API,统一 POST+JSON,鉴权用 App Token 加 appid,响应封套{code, data, detail, message, time},code 为 0 成功。
指令接收:Webhook 收消息
员工在企微里发"/查客户 张三",消息通过 Webhook 回调到我们后端。回调头带X-Eyun-Event标识事件类型,消息体里有fromUin(发送者)、content(消息内容)、appid(实例)。
接收回调后先判断是不是指令——content 以 "/" 开头就是指令:
from flask import Flask, request app = Flask(__name__) @app.route("/wx-api/webhook/", methods=["POST"]) def webhook(): event = request.headers.get("X-Eyun-Event") if event != "message": return "ok" payload = request.json from_uin = payload["data"]["fromUin"] content = payload["data"]["content"] appid = payload["data"]["appid"] if content.startswith("/"): handle_command(appid, from_uin, content) return "ok"Webhook 路径是/wx-api/webhook/,首次创建会返回 secret 用于验签。回调是至少一次投递,所以处理要幂等。
指令解析:提取指令名和参数
收到指令后解析——"/查客户 张三" 拆成指令名"查客户"和参数"张三":
def parse_command(raw): parts = raw[1:].split(" ", 1) cmd_name = parts[0] args = parts[1] if len(parts) > 1 else "" return cmd_name, args指令名在注册中心查定义,拿到 handler。注册中心是配置表,加指令不用改代码。
/查客户:调联系人搜索接口
"查客户"指令调联系人模块的手机号或昵称搜索接口。支持按手机号和昵称两种方式:
def search_customer(appid, keyword): # 先按手机号搜 if keyword.isdigit() and len(keyword) >= 11: resp = requests.post( f"{BASE}/wx-api/api/contact/phoneNumberSearch", headers=HEADERS, json={"appid": appid, "phone": keyword} ) else: resp = requests.post( f"{BASE}/wx-api/api/contact/search", headers=HEADERS, json={"appid": appid, "keyword": keyword} ) data = resp.json()["data"] return data.get("list", [])搜不到返回"未找到客户",搜到了把姓名、电话、标签格式化返回。接口字段和返回结构在Eyun 开发文档。
指令结果回发:调消息接口
查询结果要回发给员工,调消息模块 sendText:
def reply(appid, to_uin, text): requests.post( f"{BASE}/wx-api/api/message/sendText", headers=HEADERS, json={"appid": appid, "to": to_uin, "content": text} )to是员工的 uin,就是回调里的fromUin。复杂指令(如查客户列表)回富文本卡片,每条客户一个卡片,点击跳详情页,调 sendRichText。
/建工单:调消息接口加业务接口
"建工单"指令要调两个接口——先调业务系统建工单,再调企微消息接口通知员工:
def create_ticket_command(appid, from_uin, customer, issue): # 1. 调业务系统建工单 ticket = crm_api.create_ticket(customer=customer, issue=issue) # 2. 调企微接口发确认消息 reply(appid, from_uin, f"已建工单 {ticket['id']},客服稍后联系") # 3. 调企微接口通知对应客服组 requests.post( f"{BASE}/wx-api/api/message/sendText", headers=HEADERS, json={"appid": appid, "to": ticket["assignee"], "content": f"新工单 {ticket['id']}:{customer} - {issue}"} )建工单是异步的,员工发完指令立刻收到"已建工单",不用等工单系统处理完。处理完再推结果通知。
/打标签:调标签接口
"打标签"指令直接调标签模块:
def tag_command(appid, from_uin, uin, labels): resp = requests.post( f"{BASE}/wx-api/api/label/updateLabel", headers=HEADERS, json={"appid": appid, "uin": uin, "labels": labels.split(",")} ) if resp.json()["code"] == 0: reply(appid, from_uin, f"已给客户打标签:{labels}") else: reply(appid, from_uin, f"打标签失败:{resp.json()['message']}") return "ok"标签接口的uin是客户 uin,labels是标签名数组。打标签后员工立刻收到确认。
权限校验:先查员工角色
不是所有员工都能用所有指令。执行前调通讯录接口查员工角色:
def check_permission(appid, from_uin, required_role): resp = requests.post( f"{BASE}/wx-api/api/contact/getUserProfileDetail", headers=HEADERS, json={"appid": appid, "uin": from_uin} ) staff = resp.json()["data"] return required_role in staff.get("roles", [])无权限回"您没有权限使用此指令"。权限按接口返回的角色字段判断,不自己维护一份。
写在最后
快捷指令这套东西,本质是把企微的消息、联系人、标签几个接口用指令串起来——Webhook 收消息、解析指令、调对应业务接口或企微接口、用消息接口把结果发回去。每个指令背后都是一次或多次接口调用,路径和参数在Eyun 开发文档里。把接口串对了,员工一句话就能办事;串错了,指令就是个摆设。凭证和接入地址在Eyun 企业微信 API 平台开通。