APP渠道集成

您已拥有一款手机APP,只需在环信移动客服系统创建“APP关联”,并集成环信提供的SDK,即可轻松实现APP接入。

APP SDK集成

环信为您提供了移动客服Android SDK和iOS SDK,两个SDK均基于环信即时通讯云(IM) SDK 3.x,只需5分钟即可集成移动客服通用功能。

“商城”demo源码:

如果您的APP已集成IM SDK 2.x,您也可以打开“商城”demo源码的地址,跳转到“旧版商城demo源码”,参考“旧版商城demo源码”集成移动客服的基本功能。

注:集成过程中有任何技术问题,请联系环信技术支持。

APP扩展集成

APP用户端可通过消息中增加ext扩展字段的方式,实现更多个性化功能集成。

以下功能,移动客服Android SDK和iOS SDK已默认支持,或通过调用API可以集成。下述通过ext扩展字段集成的方式仅供参考。

显示用户信息

当访客咨询客服时,客服可以在会话窗口旁边看到该访客的用户信息,包括:昵称、名字、手机、QQ、邮箱、公司名称、备注等。

APP传递消息格式:

//例如:有个真名叫李明,昵称小明的访客,已经提供了QQ号,公司名和联系方式等信息。
{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "visitor":{  
        "trueName":"李明",
        "qq":"13512345678",
        "companyName":"环信",
        "userNickname":"小明",
        "description":"",
        "email":"abc@123.com"
      }
    }
  }
}

注:会话过程中,如果客服对访客的资料进行了编辑,则显示客服编辑后的访客资料。

显示客服头像和昵称

访客发起咨询时,可以在APP聊天界面显示正在接待的客服头像和昵称。需要进入“管理员模式→设置→系统开关”,打开“访客端显示客服昵称”开关。

开关打开后,在客服发向访客的消息里面就会包含agent信息的扩展字段,具体如下:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "agent":{  
        "userNickname":" ",
        "avatar":" "
      },
      "visitor":{  

      }
    }
  }
}

APP端可以获取昵称(userNickname)和头像(avatar),然后在UI上做展示。

显示转接提示

客服转接会话时,APP访客端显示转接提示(如转接中,请稍候…),以便用户知道客服服务状态。该功能需要联系环信开通,并且UI需APP自定义。

开通该功能后,在客服人员进行会话转接时,在消息ext里面增加了事件(event)字段,并监听会话转接,在收到会话转接的事件时,把这个事件通过透传消息发送给访客端。访客端需要隐藏该透传消息,根据eventName自定义转接提示的UI,并做相关测试。

发给访客端的透传消息格式如下:

{  
  "msg":{  
    "type":"cmd",
    "action":"transfer"
  },
  "from":"test", //表示这个消息是谁发出来的, 可以没有这个属性, 那么就会显示是admin, 如果有的话, 则会显示是这个用户发出的。
  "ext":{  
    "weichat":{  
      "agent":{  
        "userNickname":" ",
        "avatar":" "
      },
      "event":{  
        "eventName":"ServiceSessionTransferedEvent",
        "eventObj":null
      }
    }
  }
}

指定客服

为APP的“联系客服”按钮指定一位明确的客服人员,当用户从该按钮发起的会话将只分配给该客服。

指定规则由APP自定义。

具体实现方法如下:

调用EMMessage的扩展消息,关键字段为agentUsername。

消息格式:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "agentUsername":"xxx@xxx.com"
    }
  }
}

其中,agentUsername为客服登录邮箱。

注:当会话同时指定了客服和技能组时,以指定客服为准,指定技能组失效。

指定技能组

为APP的“联系客服”按钮指定一个技能组,当用户从该按钮发起的会话将只分配给该技能组内的客服。可以添加多个按钮,分别指定不同技能组。

技能组名称须和客服系统设置的技能组名称完全一致,中英文均可。

消息格式:

例如:在环信移动客服系统设置一个技能组名称为“售前”,当APP客户端发送带有扩展字段“售前”的消息到服务器时,系统会将此会话自动分配给“售前”技能组处理。

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "queueName":"售前"
    }
  }
}

注:

  • 当没有指定技能组时,系统默认将会话分配给未分技能组的客服。
  • 当会话同时指定了客服和技能组时,以指定客服为准,指定技能组失效。

VIP访客插队

当客服全忙时,VIP访客可插队到队首,有空闲坐席出现时,优先接入。

访客发起会话时,APP端通过消息扩展中的”tags”字段标出VIP用户,凡是”tags”字段非空的访客都会直接排在待接入队列的最前面。当有多个访客包含非空的”tags”字段时,这些访客单独按会话发起时间排队。

具体实现方法如下:

在EMMessage扩展消息的visitor关键字段内,增加tags属性,其值可以为零到多个。当访客发起会话时,通过该扩展消息将访客tags属性传到客服系统,系统即可把该访客放在待接入队列的最上面。

消息格式:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "visitor":{  
        "tags":[  
          "vip1",
          "vip2"
        ]
      }
    }
  }
}

显示满意度评价邀请

APP需做以下集成,才能正常显示由客服发送的满意度评价邀请。UI需APP自定义。

具体实现方法如下:

调用EMMessage的扩展消息,关键字段为weichat和ctrlType。

客服端发给访客端的评价邀请

ctrlType:inviteEnquiry
ctrlArgs:

inviteId 必选服务端发送会话相关ID。
serviceSessionId必选服务端发送会话相关ID。
detail 可选在客户端默认显示在对话框中的内容。
summary 可选客户端默认显示的满意度级别。

消息示例:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "ctrlType":"inviteEnquiry",
      "ctrlArgs":{  
        "inviteId":1,
        "serviceSessionId":"5e7e8815-99d9-45fd-9bef-4918795a0885",
        "detail":null,
        "summary":null
      }
    }
  }
}

访客端返回给客服端的评价结果

ctrlType:enquiry
ctrlArgs:

inviteId 必选返回服务端发送过来的相应内容即可,客户端主动发起时设置为““。
serviceSessionId必选返回服务端发送过来的相应内容即可,客户端主动发起时设置为”“。
detail 必选用户在客户端输入框输入的相应内容。
summary 必选用户选择的级别。注:目前仅有1~5是有效数据,超出此范围会被识别为无效评价,不计入平均分也不会统计进有效评价

消息示例:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "ctrlType":"enquiry",
      "ctrlArgs":{  
        "inviteId":1,
        "serviceSessionId":"5e7e8815-99d9-45fd-9bef-4918795a0885",
        "detail":"非常好",
        "summary":"1"
      }
    }
  }
}

发送轨迹消息

当APP用户浏览某个商品页时点击“联系客服”,APP可自动将该商品链接发送给客服。

要实现该功能,需在消息中增加扩展字段msgtype。

消息格式:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "msgtype":{  
      // 用户轨迹消息 
      "track":{  
        // 消息标题 
        "title":"我正在看:",
        // 商品价格 
        "price":"¥: 235.00",
        // 商品描述 
        "desc":"女装小香风气质蕾丝假两件短袖",
        // 商品图片链接 
        "img_url":"https://yourdomain.com/img/a.jpg",
        // 商品页面链接 
        "item_url":"https://yourdomain.com/item/a.html"
      }
    }
  }
}

发送轨迹消息

发送订单消息

当APP用户浏览某个订单页时点击“联系客服”,APP可自动将该订单链接发送给客服。

要实现该功能,需在消息中增加扩展字段msgtype。

消息格式:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "msgtype":{  
      // 订单消息 
      "order":{  
        // 消息标题 
        "title":"我的订单",
        // 订单标题 
        "order_title":"订单号:a110083",
        // 商品价格 
        "price":"¥: 235.00",
        // 商品描述 
        "desc":"女装小香风气质蕾丝假两件短袖",
        // 商品图片链接 
        "img_url":"https://yourdomain.com/img/a.jpg",
        // 商品页面链接 
        "item_url":"https://yourdomain.com/item/a.html"
      }
    }
  }
}

发送订单消息

显示机器人菜单消息

机器人菜单消息包括两种:(1)在“自定义菜单”配置的菜单;(2)相似问句推荐。其中,菜单消息中包含的“转人工客服”是文本消息,对应示例代码中的“列表内容”。

APP需做以下集成,才能正常显示由机器人发送的菜单消息。UI需APP自定义。

具体实现方式:

调用EMMessage的扩展消息,关键字段为msgtype和choice,可以对回复的机器人菜单进行识别。集成时需要能够显示以下两种格式的菜单消息。

消息格式1(在“自定义菜单”中配置的菜单):

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "msgtype":{  
      "choice":{  
        "items":[  
          {  
            "id":"xxx",
            "name":"1.列表内容"
          },
          {  
            "id":"xxx",
            "name":"2.列表内容"
          }
        ],
        "title":"列表的标题"
      }
    }
  }
}

消息格式2(相似问句推荐):

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "msgtype":{  
      "choice":{  
        "title":"列表的标题",
        "list":[  
          "1.列表内容...",
          "2.列表内容..."
        ]
      }
    }
  }
}

显示机器人转人工客服按钮

为机器人默认回复添加的“转人工客服”为按钮形式。在后台配置显示转人工按钮时,机器人发送过来的消息包含特定的扩展,需要检查并把转人工按钮显示出来。

实现方式:

调用EMMessage的扩展消息,关键字段为TransferToKfHint。

消息格式:

{  
  "msg":{  
    "type":"txt",
    "msg":" "
  },
  "ext":{  
    "weichat":{  
      "ctrlType":"TransferToKfHint",
      "ctrlArgs":{  
        "id":"xxx",
        "serviceSessionId":"xxx-xxx-xxx",
        "lable":"转人工客服"
      }
    }
  }
}

当点击转人工客服按钮时,发送一条透传消息,并把id、serviceSessionId和ctrlArgs通过扩展带过去。移动客服Android SDK默认支持该功能;使用其他方式集成时,请参考iOS和Android版商城demo。

格式如下:

{  
  "msg":{  
    "type":"cmd",
    "action":"TransferToKf"
  },
  "ext":{  
    "weichat":{  
      "ctrlArgs":{  
        "id":"xxx",
        "serviceSessionId":"xxx-xxx-xxx"
      }
    }
  }
}

集成留言功能

使用下文中的REST API实现留言的界面。

集成前的准备

集成留言功能前,需获取以下数据:

  • 当前租户的tenantId。前往“管理员模式 > 设置 > 企业信息”页面查看,并记录下来;
  • 留言项目的Project ID。前往“管理员模式 > 留言”页面查看,并记录下来;
  • 对接移动客服的AppKey和IM服务号。前往“管理员模式 > 渠道管理 > 手机APP”页面,点击关联的“编辑”按钮查看,并记录下来;
  • 访客的visitorId(环信ID);
  • 该访客对应环信IM用户的token。

注:当前只支持通过环信IM这个渠道的访客端集成。

获取IM用户的token

使用以下REST API获取IM用户的token。Path前需加上域名,示例:https://a1.easemob.com/easemob-demo/chatdemoui/token

  • Path: /{org_name}/{app_name}/token
  • HTTP Method: POST
  • URL Params: 无
  • Request Headers: {“Content-Type”:“application/json”}
  • Request Body:
    {"grant_type": "password", "username": "{IM用户的用户名}", "password": "{IM用户的密码}"}

创建留言

使用以下REST API创建留言。创建语音留言时,请将附件类型设置为audio。Path需填写tenantId所在的域名,示例:https://kefu.easemob.com/tenants/2112/projects/2/tickets

  • Path: /tenants/:tenantId/projects/:projectId/tickets
  • HTTP Method: POST
  • URL Params: {“easemob-appkey”:“${orgName%23appName}”,“easemob-username”:“${visitorId}”,“easemob-target-username”:“${IM服务号}”}
  • Request Headers: {“Content-Type”:“application/json”,“Authorization”:“Easemob IM ${token}”}
  • Request Body:
{
    "subject": "留言的主题",   // 可选, 如果没有的话, 那么默认是content的前20个字
    "content": "留言的主要内容",
    "status_id": "留言的默认处理状态",   //  可选, 如果没有则使用project定义的默认的status, 如果没有定义默认的status则留空
    "priority_id": "优先级",   // 可选, 如果没有则使用project定义的默认的priority, 如果没有定义默认的priority则留空
    "category_id": "类别",    // 可选, 如果没有则使用project定义的默认的category, 如果没有定义默认的category则留空
    "origin_type": "渠道类型", // 可选, 参数的值为app, webim, weixin, weibo, 如果没有则默认为app
    "creator": {    // 留言的创建者
        "name": "创建这个留言的访客的名称",
        "avatar": "创建这个留言的访客的头像",   // 可选
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "attachments":[{    // 留言的附件
        "name": "该附件的名称",
        "url": "该附件的url",    // 附件需上传到您自己的服务器
        "type": "附件的类型, 当前支持image, file和audio"
    }]
}

获取全部留言

默认情况下,会返回此项目中创建者为此访客的最新的10个留言。Path需填写tenantId所在的域名,示例:https://kefu.easemob.com/tenants/2112/projects/2/tickets

  • Path: /tenants/:tenantId/projects/:projectId/tickets
  • HTTP Method: GET
  • URL Params: {“easemob-appkey”:“${orgName%23appName}”,“easemob-username”:“${visitorId}”,“easemob-target-username”:“${IM服务号}”}
  • Request Headers: {“Content-Type”:“application/json”,“Authorization”:“Easemob IM ${token}”}
  • Request Body: 无

URL Params还可以添加以下查询参数:

  • statusId: 按状态id过滤(可选,默认返回所有状态的留言)
  • categoryId: 按分类id过滤(可选,默认返回所有分类的留言,-1表示过滤未分类的留言)
  • assignee: 按处理者的id过滤。分配给谁的id或者none(区分大小写)来表示获取所有未分配的留言(可选,默认返回所有的处理人的留言)
  • startTime, endTime: timestamp类型的参数,用来按时间段来查询留言,取创建时间(可选,默认返回所有的创建时间的留言)
  • creator 按创建者的id过滤

返回值(忽略了分页部分的数据结构):

"entities": [{
    "id": "此ticket的id, long类型",
    "status": {
        "id": "此status的id",
        "name": "此status的name"
    },
    "subject": "留言的主题,可选,如果没有的话,那么默认是content的前20个字",
    "content": "留言的主要内容",
    "origin_type": "渠道类型",
    "creator": {
        "id": "此ticket的创建者的id",
        "name": "此ticket的创建者的name",
        "agentNumber":"创建这个ticket的人如果是座席,座席的工号,如果是访客,没有这个字段" ,
        "avatar": "此ticket的创建者的头像",
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "assignee": {
        "id": "此ticket的处理者的id",
        "name": "此ticket的处理者的name",
        "agentNumber":"处理这个ticket的人的工号",
        "avatar": "此ticket的处理者的头像",
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    }
}]

注:

  • 出于安全考虑,访客端查询的时候,只会返回创建者为此访客的留言,也就是访客只能查看自己创建的留言,而不能查看别人创建的。
  • 并且这个api只会返回ticket的基本信息,并不包括所有的comments,是为了供列表展示用。

分页

所有的查询一组数据的API,例如获取全部的留言(tickets),都是支持分页的,并且有默认的大小。

  • page:第几页,从0开始,默认为第0页
  • size:每一页的大小,默认为10,最大不能超过100
  • sort:排序相关的信息,以property,property(,ASC|DESC)的方式组织,例如sort=firstname&sort=lastname,desc表示在按firstname正序排列基础上按lastname倒序排列,默认为创建时间(created_at属性)

例如,获取全部留言(tickets)的API,可以写成:

GET /tenants/:tenantId/projects/:projectId/tickets?page=3&size=29&sort=createdAt,desc&sort=priorityId,asc

这样,会返回第三页的数据,包括最多29个tickets,并且会先按照创建时间倒序排列然后在按照优先级升序排列。

返回结果中包括了分页的相关信息,例如包括如下的属性:

  • first: 是否是第一页,true 或者false
  • last: 是否是最后一页,true或者false
  • totalPages: 总共有多少页
  • size: 每页大小
  • number: 当前页为第几页,从0开始
  • numberOfElements: 当前页一共有多少数据
  • entities: 数据,包括了所有这个页面中的数据

获取留言详情

根据留言ID获取一个留言的详情。Path需填写tenantId所在的域名,示例:https://kefu.easemob.com/tenants/2112/projects/2/tickets/10001

  • Path: /tenants/:tenantId/projects/:projectId/tickets/:ticketId
  • HTTP Method: GET
  • URL Params: {“easemob-appkey”:“${orgName%23appName}”,“easemob-username”:“${visitorId}”,“easemob-target-username”:“${IM服务号}”}
  • Request Headers: {“Content-Type”:“application/json”,“Authorization”:“Easemob IM ${token}”}
  • Request Body: 无

返回值:

{
    "id": "long类型的id",
    "origin_type": "渠道类型",
    "status": {    // 当前状态
        "id": "这个status对应的id",
        "name": "这个status对应的名称",
        "description": "这个status对应的描述",
        "icon_url": "这个status对应的图标的url"
    },
    "attachments":[{  // 附件
        "id": "附件的id",
        "name": "该附件的名称",
        "url": "该附件的url",
        "type": "附件的类型, 当前支持image, file和audio"
    }],
    "subject": "留言的主题,可选,如果没有的话,那么默认是content的前20个字",
    "content": "留言的主要内容",
    "creator": {  // 创建者
        "id": "创建这个评论的人的id",
        "username": "创建这个ticket的人的环信ID",
        "name": "创建这个ticket的人的name",
        "avatar": "创建这个ticket的人的头像",
        "type": "创建这个ticket的人的类型, 例如是坐席还是访客",
        "agentNumber":"创建这个ticket的人如果是座席,座席的工号,如果是访客,没有这个字段" ,
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "assignee": {  // 留言被分配给了谁
        "id": "这个留言被分配给了谁",
        "username": "处理这个留言的人的环信ID",
        "name": "处理这个留言的人的name",
        "avatar": "处理这个留言的人的头像",
        "type": "处理这个留言的人的类型,例如是坐席还是访客",
        "agentNumber":"处理这个ticket的人的工号",
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "created_at": "创建时间",
    "updated_at": "修改时间"
}

注:出于安全考虑,访客端查询的时候,只会返回创建者为此访客的留言,也就是访客只能查看自己创建的留言,而不能查看别人创建的。

对留言进行评论

给一个留言添加评论。添加语音评论时,请将附件类型设置为audio。Path需填写tenantId所在的域名,示例:https://kefu.easemob.com/tenants/2112/projects/2/tickets/10001/comments

  • Path: /tenants/:tenantId/projects/:projectId/tickets/:ticketId/comments
  • HTTP Method: POST
  • URL Params: {“easemob-appkey”:“${orgName%23appName}”,“easemob-username”:“${visitorId}”,“easemob-target-username”:“${IM服务号}”}
  • Request Headers: {“Content-Type”:“application/json”,“Authorization”:“Easemob IM ${token}”}
  • Request Body:
{
    "subject": "评论的主题, 可选",
    "content": "评论的内容",
    "reply": {
        "id": "回复的哪条评论的id, 可选"
    },
    "creator": {
        "id": "创建这个评论的人的id,可选",
        "username": "创建这个comment的人的环信ID",
        "name": "创建这个comment的人的name",
        "avatar": "创建这个comment的人的头像",
        "type": "创建这个comment的人的类型, 例如是坐席还是访客",
        "agentNumber":"创建这个comment的人如果是座席,座席的工号,如果是访客,没有这个字段" ,
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "attachments":[{
        "name": "该附件的名称",
        "url": "该附件的url",   // 附件需上传到您自己的服务器
        "type": "附件的类型, 当前支持image, file和audio"
    }], 
    "status_id": "status 的id" //设置了这个属性的话, 可以在添加评论的时候同时设置这个ticket的状态, 只有agent能够调用
}

获取留言评论

根据留言ID获取一个留言的评论。Path需填写tenantId所在的域名,示例:https://kefu.easemob.com/tenants/2112/projects/2/tickets/10001/comments

  • Path: /tenants/:tenantId/projects/:projectId/tickets/:ticketId/comments
  • HTTP Method: GET
  • URL Params: {“easemob-appkey”:“${orgName%23appName}”,“easemob-username”:“${visitorId}”,“easemob-target-username”:“${IM服务号}”}
  • Request Headers: {“Content-Type”:“application/json”,“Authorization”:“Easemob IM ${token}”}
  • Request Body: 无

返回值(忽略了分页部分的数据结构):

"entities":[  
  {  
    "id":"long类型的id",
    "subject":"评论的主题, 可选",
    "content":"评论的内容",
    "reply":{  
      "id":"回复的哪条评论的id, 可选"
    },
    "creator":{  
      "id":"创建这个评论的人的id",
      "username":"创建这个comment的人的环信ID",
      "name":"创建这个comment的人的name",
      "avatar":"创建这个comment的人的头像",
      "type":"创建这个comment的人的类型, 例如是坐席还是访客",
      "agentNumber":"创建这个comment的人如果是座席,座席的工号,如果是访客,没有这个字段",
      "email":"电子邮件地址",
      "phone":"电话号码",
      "qq":"qq号码",
      "company":"公司",
      "description":"具体的描述信息"
    },
    "attachments":[  
      {  
        "name":"该附件的名称",
        "url":"该附件的url",
        "type":"附件的类型, 当前支持image, file和audio"
      }
    ],
    "created_at":"创建时间",
    "updated_at":"修改时间"
  }
]

分页

获取留言评论(comments)支持分页,并且有默认的大小。

  • page:第几页,从0开始,默认为第0页
  • size:每一页的大小,默认为10,最大不能超过100
  • sort:排序相关的信息,以property,property(,ASC|DESC)的方式组织,例如sort=firstname&sort=lastname,desc表示在按firstname正序排列基础上按lastname倒序排列,默认为创建时间(created_at属性)

例如,获取留言评论的API,可以写成:

GET /tenants/:tenantId/projects/:projectId/tickets/:ticketId/comments?page=3&size=29&sort=createdAt,desc&sort=priorityId,asc

这样,会返回第三页的数据,包括最多29个comments,并且会先按照创建时间倒序排列然后在按照优先级升序排列。

返回结果中包括了分页的相关信息,例如包括如下的属性:

  • first: 是否是第一页,true 或者false
  • last: 是否是最后一页,true或者false
  • totalPages: 总共有多少页
  • size: 每页大小
  • number: 当前页为第几页,从0开始
  • numberOfElements: 当前页一共有多少数据
  • entities: 数据,包括了所有这个页面中的数据

APP端接收留言通知

一个人创建了留言之后,如果有别人回复了或者变更了这个留言的状态(例如把一个留言标记成已解决),留言系统能够发出通知给创建者,在手机APP端,可以在收到通知消息之后,调用上面相应的API来获取最新的变动,然后在留言的界面做展示,展示之后应该及时清除掉通知消息。

当前,留言系统只支持通过环信即时通讯云的消息扩展进行通知。

留言通知

目前支持以下留言通知。

留言状态改变

坐席改变一个留言的状态的时候,会给留言的创建者(访客的手机上)推送如下信息:

消息格式:

{
  "target" : [ "stliu0002" ],
  "msg" : {
    "type" : "txt",
    "msg" : "坐席[agent111]把留言[this is a ticket con]的状态从[未处理]变成了[已解决]"
  },
  "ext" : {
    "weichat" : {
      "notification" : true,
      "event" : {
        "eventName" : "TicketStatusChangedEvent",
        "ticket" : {
          "id" : 2000,
          "subject" : "this is a ticket con",
          "content" : "this is a ticket content",
          "version" : 0,
          "created_at" : "2016-01-10T16:43:40.914Z",
          "updated_at" : "2016-01-10T16:43:40.948Z"
        },
        "statusBefore" : {
          "id" : 1000,
          "name" : "未处理",
        },
        "statusAfter" : {
          "id" : 1001,
          "name" : "已解决",
        }
      }
    }
  }
}

新的留言评论

坐席回复一个留言的时候,会给留言的创建者(访客的手机)上推送如下的信息:

消息格式:

{
  "target" : [ "stliu0002" ],
  "msg" : {
    "type" : "txt",
    "msg" : "坐席[agent111]回复了留言[this is a ticket con], 内容是[sss]"
  },
  "ext" : {
    "weichat" : {
      "notification" : true,
      "event" : {
        "eventName" : "CommentCreatedEvent",
        "ticket" : {
          "id" : 2000,
          "subject" : "this is a ticket con",
          "content" : "this is a ticket content",
          "version" : 0,
          "created_at" : "2016-01-10T17:09:31.365Z",
          "updated_at" : "2016-01-10T17:09:31.366Z"
        },
        "comment" : {
          "id" : 3000,
          "creator" : {
            "id" : "dec9da4a-d692-43d9-9bed-9687adf8353a",
            "name" : "agent111",
          },
          "version" : 0,
          "created_at" : "2016-01-10T17:09:31.390Z",
          "updated_at" : "2016-01-10T17:09:31.390Z"
        }
      }
    }
  },
  "target_type" : "users"
}

接收通知消息

和正常接收消息一样,需要在主界面和聊天界面添加监听。详细用法可以参考商城Demo中实现。

附:留言和评论的数据结构

留言(Ticket)

留言是指一个具体的留言,其包括:

  • 创建者
  • 执行者(具体这个留言被分配给了谁)
  • 当前状态(例如是未分配,还是处理进行中,还是已解决)
  • 优先级
  • 类别
  • 如果被解决了的话,那么还包括解决方案
  • 主题
  • 具体问题的描述
  • 附件(多个)

留言的数据结构:

{
    "id": "long类型的id",
    "subject": "ticket的主题, 可选, 如果没有的话, 那么默认是content的前10个字",
    "content": "ticket的主要内容",
    "origin_type": "渠道类型",
    "status": {
        "id": "这个status对应的id",
        "name": "这个status对应的名称",
        "description": "这个status对应的描述",
        "icon_url": "这个status对应的图标的url"
    },
    "priority": {
        "id": "这个priority对应的id",
        "name": "这个priority对应的名称",
        "description": "这个priority对应的描述",
        "icon_url": "这个priority对应的图标的url"
    },
    "category": {
        "id": "这个category对应的id",
        "name": "这个category对应的名称",
        "description": "这个category对应的描述",
        "icon_url": "这个category对应的图标的url"
    },
    "creator": {
        "id": "创建这个评论的人的id",
        "username": "创建这个ticket的人的环信ID",
        "name": "创建这个ticket的人的name",
        "avatar": "创建这个ticket的人的头像",
        "type": "创建这个ticket的人的类型, 例如是坐席还是访客",
        "agentNumber":"创建这个ticket的人如果是座席,座席的工号,如果是访客,没有这个字段" ,
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "assignee": {
        "id": "这个ticket被分配给了谁",
        "username": "处理这个ticket的人的环信ID",
        "agentNumber":"处理这个ticket的人的工号",
        "name": "处理这个ticket的人的name",
        "phone":"处理这个ticket的人的手机号",
        "avatar": "处理这个ticket的人的头像",
        "type": "处理这个ticket的人的类型, 例如是坐席还是访客"
    },
    "attachments":[{
        "name": "该附件的名称",
        "url": "该附件的url",
        "type": "附件的类型, 当前支持image, file和audio"
    }],
    "created_at": "创建时间",
    "updated_at": "修改时间"
}

评论(Comment)

评论是指对一个留言的讨论,因为在解决一个留言的过程中,可能需要和留言的创建者进行多次的沟通交流,每一个消息都是一个comment。

评论包括:

  • 创建者
  • 具体内容
  • 附件(多个)
  • 是否对访客可见(因为可能涉及到多个坐席的协作)
  • 回复给特定的comment

评论的数据结构:

{
    "id": "long类型的id",
    "subject": "评论的主题, 可选",
    "content": "评论的内容",
    "reply": {
        "id": "回复的哪条评论的id, 可选"
    },
    "creator": {
        "name": "创建这个comment的人的name",
        "avatar": "创建这个comment的人的头像",
        "agentNumber":"创建这个comment的人如果是座席,座席的工号,如果是访客,没有这个字段" ,
        "email": "电子邮件地址",
        "phone": "电话号码",
        "qq": "qq号码",
        "company": "公司",
        "description": "具体的描述信息"
    },
    "attachments":[{
        "name": "该附件的名称",
        "url": "该附件的url",
        "type": "附件的类型, 当前支持image, file和audio"
    }],
    "created_at": "创建时间",
    "updated_at": "修改时间"
}