Web常用工具 二维码美化 在线压缩 JavaScript JSON工具 JavaScript AI工具汇总网站 BASE64转换 狂神博客园 图片轮播插件(swiper) W3CHTML W3SCHOOL TypeScript 开源中国 51aspx github codeproject SQLBACKUP 几种排序算法比较 SQL中deny权限 MSDN下载 HttpWebRequest类 HTML5 stackoverflow ASP.NET 页生命周期概述 IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述 [SQL Server]视图sys.sysprocesses brnshop学习 SQL视频 Fiddler帮助文档 Sprint.Net SQLServer牛人博客 codeplex IIS官网 IE11 Developer Jquery源码视频上 Jquery源码视频下 Jquery Bugs jquery.miaov.com 正则表达式 Jquery API 1.9 Service Broker Javascript Object中的方法讲解 Microsoft webcast 微信开发接口 ECMAScript5 Underscore Jquery Bugs SQL存储过程事务嵌套 官网SQL事务锁 2345天气插件 Json数据查看 Javascript设计模式 C++ jquery-plugin-validate 博学谷(传智播客) Swift视频 IOS代码论坛 SWIFT设计模式 操作系统下载 AngularJS VueJS Nuxt Vant-UI官方文档 ASPNETCORE 前端题库 Node.js NPMjs ASPNETCORE 腾讯课堂 SwiftUI SwiftUI疑问解答 ADO.NET SMO 数字化企业网 Unicode码查询 Redis使用文档 .NET 微服务:适用于容器化 .NET 应用程序的体系结构 .NETCore5.0微软官方文档 CSS3.0 在 ASP.NET Core 中配置 Windows 身份验证 Maven使用教程 Maven Repository Thymeleaf Thymeleaf中文CSDN Spring官方文档 SpringBoot SpringData SVG在线设计工具 SVG教程01 SVG教程02 fontawesome图标库 mybatis官网 mybatis-spring中文网 mysql教程 python教程 python的scrapy教程01 python的scrapy教程02 VS开发python xpath教程 腾讯向量数据库教程 JSZip浏览器内存中创建文件与文件夹 axios的使用文档 SheetJS(JS操作excel)的使用文档 极简插件官网(chrome的扩展插件) 金蝶云星空学习成长 常用接口调用 ThreeJS中文网 D3.js官网 anime.js官网 gsap.js官网 xlsx.js官网 若依框架 若依文档 华为数字人 MDN之JavaScript语法 百度地图API 百度地图API案例 百度地图API使用说明 Nginx中文文档 i18n Animate.css Bootstrap官网 Jquery datatables.net插件 免费SVG C#官网 phet小学初中高中数理化 Pixi.js中文网 webgl教程 unity资源商店国际版 unity官方文档 unity官方着色器Shader unity官方论坛 微信官方文档

huaan011

 

微信小程序中的 联系客服 最基本的使用方法

微信官方文档:

 https://developers.weixin.qq.com/miniprogram/dev/server/API/kf-mgnt/kf-message/api_sendcustommessage.html

 https://developers.weixin.qq.com/miniprogram/dev/component/button.html

1.在小程序页面中添加一个连续客服的按钮:

<button open-type="contact" 
        bindcontact="handleContact"
        session-from="来源标识">
  联系客服
</button>
Page({
  handleContact(e) {
    console.log(e.detail.path)   // 用户点击的消息路径
    console.log(e.detail.query)  // 携带的参数
  }
})

用户点击后进入微信内置的客服聊天界面。

或者使用:

wx.openCustomerServiceConversation({
  sessionFrom: '你的会话来源标识',
  showMessageCard: true,
  sendMessageTitle: '您好,有什么可以帮您?',
  sendMessagePath: '/pages/index/index',
  sendMessageImg: 'https://example.com/image.png',
  success(res) {
    console.log('打开客服会话成功', res);
  },
  fail(err) {
    console.error('打开客服会话失败', err);
  }
});

官方文档:https://developers.weixin.qq.com/minigame/dev/api/open-api/customer-message/wx.openCustomerServiceConversation.html

2、进入小程序的管理平台进行设置开启消息推送,

  管理  -> 开发管理 -> 开发设置 -> 消息推送 -> 开启,注意消息的格式要设置成 JSON格式,默认的是 XML 格式,我的代码中全都使用的是json格式解析的。

 Token和EncodingAESKey主要是用于设置 消息推送URL(服务器地址)  时候校验地址是否正确的,下面的代码中 WeChatCustomerService方法的get方法就是校验使用的。

 

企业微信截图_17885128906914

 

3、我用的后台处理是用netCore,

/// <summary>
/// 客服消息处理
/// </summary>
/// <returns></returns>
//[HttpPost]
public async Task<IActionResult> WeChatCustomerService()
{
    // GET 请求 = 微信服务器配置 URL 时的签名验证
    if (Request.Method.ToUpper() == "GET")
    {
        var signature = Request.Query["signature"].ToString();
        var timestamp = Request.Query["timestamp"].ToString();
        var nonce = Request.Query["nonce"].ToString();
        var echostr = Request.Query["echostr"].ToString();
        return Ok(echostr); //ValidSignature();
    }
    // POST 请求 = 接收用户消息
    string _postBody = await GDCUtility.GetRequestBody();
    string resultInfoModel=await GDCWeChatCustomerServiceHelper.HandleMessageAsync(_postBody);
    return Ok(resultInfoModel);
}
/// <summary>
/// 微信客服的帮助类
/// </summary>
public class GDCWeChatCustomerServiceHelper
{
    private readonly static IMemoryCache _cache=new MemoryCache(new MemoryCacheOptions());

    #region 一个简单的接受客户的消息并处理的过程,以后都可以参考这个来扩展
    public static async Task<String> HandleMessageAsync(string postBody)
    {
        try
        {
            // using var reader = new StreamReader(Request.Body, Encoding.UTF8);
            var body = postBody; // await reader.ReadToEndAsync();
            //_logger.LogDebug("收到微信消息: {Body}", body);
            GDCLogHelper.AddLog($"收到微信消息: {body}", "HandleMessageAsync",Modules.AccessData);

            if (string.IsNullOrWhiteSpace(body))
            {
                return "success";
            }

            var msg = JsonSerializer.Deserialize<WxMessageModel>(body);
            if (msg == null)
            {
                return "success";
            }

            // 排重:防止微信重试导致重复处理
            var msgKey = $"wx_msg_{msg.FromUserName}_{msg.CreateTime}_{ (msg.MsgId==null ?  msg.EventKey : msg.MsgId.ToString()) }";
            if (_cache.TryGetValue(msgKey, out _))
            {
                //_logger.LogInformation("消息已处理,跳过重复推送: {Key}", msgKey);
                return "success";
            }
            _cache.Set(msgKey, true, TimeSpan.FromMinutes(5));

           // GDCLogHelper.AddLog($"收到微信消息MsgType: {msg.MsgType?.ToLower()}", "HandleMessageAsync", Modules.AccessData);
            // 根据消息类型分发处理
            switch (msg.MsgType?.ToLower())
            {
                case "text":
                    await HandleTextMessageAsync(msg);
                    break;

                case "image":
                    await HandleImageMessageAsync(msg);
                    break;

                case "event":
                    await HandleEventMessageAsync(msg);
                    break;

                default:
                    //_logger.LogInformation("收到未处理的消息类型: {MsgType}", msg.MsgType);
                    break;
            }
        }
        catch (Exception ex)
        {
            //_logger.LogError(ex, "处理微信消息异常");
        }

        // 必须返回 success,否则微信会重试3次
        return "success";
    }

    /// <summary>
    /// 处理文字消息
    /// </summary>
    private static async Task HandleTextMessageAsync(WxMessageModel msg)
    {
        // _logger.LogInformation("用户[{Openid}]发送文字: {Content}", msg.FromUserName, msg.Content);

        //GDCLogHelper.AddLog($"用户[{msg.FromUserName}]发送文字: {msg.Content}", "HandleMessageAsync", Modules.AccessData);

        // 简单关键词回复,实际可接入 NLP/AI
        var reply = msg.Content switch
        {
            "1" => "【订单查询】请输入您的订单号",
            "2" => "【售后服务】请描述您遇到的问题",
            "帮助" or "help" => "回复数字选择服务:\n1. 订单查询\n2. 售后服务\n3. 联系人工客服",
            _ => $"收到您的消息:{msg.Content}\n客服正在处理中..."
        };

        await SendCustomerMessageAsync(msg.FromUserName, reply);
    }

    /// <summary>
    /// 处理图片消息
    /// </summary>
    private static async Task HandleImageMessageAsync(WxMessageModel msg)
    {
        // _logger.LogInformation("用户[{Openid}]发送图片: {PicUrl}", msg.FromUserName, msg.PicUrl);
        await SendCustomerMessageAsync(msg.FromUserName, "收到图片,客服正在查看,请稍候...");
    }

    /// <summary>
    /// 处理事件消息(用户进入客服会话等),第一次点 联系客服 之类 的进入
    /// </summary>
    private static async Task HandleEventMessageAsync(WxMessageModel msg)
    {
        if (msg.Event == "user_enter_tempsession")
        {
           // _logger.LogInformation("用户[{Openid}]进入客服会话", msg.FromUserName);

            // 发送欢迎语 + 菜单
            var welcome = "👋 您好!欢迎来到客服中心\n\n" +
                          "回复数字选择服务:\n" +
                          "1️⃣ 订单查询\n" +
                          "2️⃣ 售后服务\n" +
                          "3️⃣ 联系人工客服\n\n" +
                          "或输入您的问题,智能客服为您解答";

            await SendCustomerMessageAsync(msg.FromUserName, welcome);
        }
    }


    #endregion

    #region 基本的给用户发送消息方法

    /// <summary>
    /// 发送文本客服消息
    /// </summary>
    public static async Task<bool> SendCustomerMessageAsync(string openid, string content)
    {
        var accessToken = GDCWeChatAppHelper.GetAccessToken();
        var url = $"https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={accessToken}";
        var payload = new
        {
            touser = openid,
            msgtype = "text",
            text = new { content }
        };
        //这个会对 导致 👋 被转成了 \uD83D\uDC4B
        //var json = JsonSerializer.Serialize(payload, new JsonSerializerOptions
        //{
        //    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        //    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping //防止转义
        //});

        var json = Newtonsoft.Json.JsonConvert.SerializeObject(payload);

        Console.WriteLine(json);

        var response =GDCHttpRequestHelper.HttpPostString(url,json,"", "application/json", "application/json").Result;
        //var result = await response.Content.ReadAsStringAsync();

        //_logger.LogDebug("发送客服消息结果: {Result}", result);
        //GDCLogHelper.AddLog($"发送客服消息结果: {response}", "HandleMessageAsync", Modules.AccessData);
        var wxRes = JsonSerializer.Deserialize<WxResponseModel>(response);
        if (wxRes?.ErrCode != 0)
        {
            // _logger.LogError("发送客服消息失败: {ErrCode} {ErrMsg}", wxRes?.ErrCode, wxRes?.ErrMsg);
            //GDCLogHelper.AddLog($"发送客服消息失败: {wxRes?.ErrCode} {wxRes?.ErrMsg}", "HandleMessageAsync", Modules.AccessData);
            return false;
        }
        return true;
    }


    /// <summary>
    /// 发送小程序卡片(引导用户跳转页面)
    /// </summary>
    public static async Task<bool> SendMiniProgramCardAsync(string openid, string title, string pagePath, string thumbMediaId)
    {
        var accessToken = GDCWeChatAppHelper.GetAccessToken();
        var url = $"https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={accessToken}";

        var payload = new
        {
            touser = openid,
            msgtype = "miniprogrampage",
            miniprogrampage = new
            {
                title,
                pagepath = pagePath,
                thumb_media_id = thumbMediaId
            }
        };
        //这个会对 导致 👋 被转成了 \uD83D\uDC4B
        //var json = JsonSerializer.Serialize(payload, new JsonSerializerOptions
        //{
        //    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        //    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping //防止转义
        //});

        var json = Newtonsoft.Json.JsonConvert.SerializeObject(payload);

        var response = GDCHttpRequestHelper.HttpPostString(url,json,"", "application/json", "application/json").Result;
        //var result = await response.Content.ReadAsStringAsync();
        var wxRes = JsonSerializer.Deserialize<WxResponseModel>(response);
        return wxRes?.ErrCode == 0;
    }

    #endregion
}

/// <summary>
/// 微信推送的消息结构
/// </summary>
public class WxMessageModel
{
    [JsonPropertyName("ToUserName")]
    public string ToUserName { get; set; }

    [JsonPropertyName("FromUserName")]
    public string FromUserName { get; set; }

    [JsonPropertyName("CreateTime")]
    public long CreateTime { get; set; }

    [JsonPropertyName("MsgType")]
    public string MsgType { get; set; }

    [JsonPropertyName("MsgId")]
    public long? MsgId { get; set; }

    [JsonPropertyName("Content")]
    public string Content { get; set; }

    [JsonPropertyName("PicUrl")]
    public string PicUrl { get; set; }

    [JsonPropertyName("MediaId")]
    public string MediaId { get; set; }

    [JsonPropertyName("Event")]
    public string Event { get; set; }

    [JsonPropertyName("EventKey")]
    public string EventKey { get; set; }

    [JsonPropertyName("SessionFrom")]
    public string SessionFrom { get; set; }
}
/// <summary>
/// 微信接口通用响应
/// </summary>
public class WxResponseModel
{
    [JsonPropertyName("errcode")]
    public int ErrCode { get; set; }

    [JsonPropertyName("errmsg")]
    public string ErrMsg { get; set; }
}

4、运行的效果

企业微信截图_1788513297858

 

企业微信截图_17885132706759

 

ffb676e1b5e287ee9c62c8d825b4176

 

重要说明:

如果小程序后台配置了多名客服,消息会由系统根据在线情况分配给相应客服,

  • 消息会由微信的客服系统自动根据在线状态和接待能力等规则分配给具体某个在线客服。
  • 开发者和小程序端无法控制或指定具体将用户消息分配给哪位客服。
  • 系统会优先分配给在线且空闲的客服,保证用户能尽快获得响应。

这个自动分配机制是微信官方托管的,目的是均衡客服工作量和提升用户体验。

 

如果还想更多的要求,就自己动手仔细研究。。。

posted on 2026-09-04 17:15  华安  阅读(19)  评论(0)    收藏  举报

导航