mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-07-15 14:04:32 +08:00
feat(openai): 新增第三方客服接入相关接口
This commit is contained in:
parent
cf49b5fe83
commit
3d432ceb85
@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 userEnter 事件的数据。</para>
|
||||
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/thirdkefu/recivemsg.html </para>
|
||||
/// </summary>
|
||||
public class UserEnterEvent : WechatOpenAIEvent, WechatOpenAIEvent.Serialization.IXmlSerializable
|
||||
{
|
||||
public static class Types
|
||||
{
|
||||
public class Content
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置消息。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("msg")]
|
||||
public string Message { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置用户 ID。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("userid")]
|
||||
public string UserId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置对话来源。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("from")]
|
||||
public string From { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置消息内容。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("content")]
|
||||
public Types.Content? Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置客服接入状态。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("status")]
|
||||
public int Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置渠道。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("channel", IsNullable = true)]
|
||||
public string? Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置用户评价。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("assessment", IsNullable = true)]
|
||||
public int? Assessment { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 userQuit 事件的数据。</para>
|
||||
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/thirdkefu/recivemsg.html </para>
|
||||
/// </summary>
|
||||
public class UserQuitEvent : UserEnterEvent
|
||||
{
|
||||
}
|
||||
}
|
@ -98,18 +98,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
|
||||
try
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = new System.Xml.XmlTextWriter(stream, Encoding.UTF8);
|
||||
writer.Formatting = System.Xml.Formatting.None;
|
||||
|
||||
XmlSerializer xmlSerializer = new XmlSerializer(typeof(TEvent), new XmlRootAttribute("xml"));
|
||||
XmlSerializerNamespaces xmlNamespace = new XmlSerializerNamespaces();
|
||||
xmlNamespace.Add(string.Empty, string.Empty);
|
||||
xmlSerializer.Serialize(writer, callbackModel, xmlNamespace);
|
||||
writer.Flush();
|
||||
xml = Encoding.UTF8.GetString(stream.ToArray());
|
||||
xml = Regex.Replace(xml, "\\s+<\\w+ (xsi|d2p1):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
|
||||
xml = Regex.Replace(xml, "<\\?xml[^>]*\\?>", string.Empty, RegexOptions.IgnoreCase);
|
||||
xml = Utilities.XmlUtility.Serialize(callbackModel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flurl;
|
||||
using Flurl.Http;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
{
|
||||
public static class WechatOpenAIClientExecuteOpenApiThirdKfExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>异步调用 [POST] /openapi/sendmsg/{TOKEN} 接口。</para>
|
||||
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/thirdkefu/sendmsg.html </para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Models.OpenApiSendMessageResponse> ExecuteOpenApiSendMessageAsync(this WechatOpenAIClient client, Models.OpenApiSendMessageRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (request is null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
IFlurlRequest flurlReq = client
|
||||
.CreateRequest(request, HttpMethod.Post, "openapi", "sendmsg", client.Credentials.PushToken!);
|
||||
|
||||
return await client.SendRequestWithJsonAsync<Models.OpenApiSendMessageResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>异步调用 [POST] /openapi/kefustate/get/{TOKEN} 接口。</para>
|
||||
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/thirdkefu/getstate.html </para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Models.OpenApiKefuStateGetResponse> ExecuteOpenApiKefuStateGetAsync(this WechatOpenAIClient client, Models.OpenApiKefuStateGetRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (request is null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
IFlurlRequest flurlReq = client
|
||||
.CreateRequest(request, HttpMethod.Post, "openapi", "kefustate", "get", client.Credentials.PushToken!);
|
||||
|
||||
return await client.SendRequestWithJsonAsync<Models.OpenApiKefuStateGetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>异步调用 [POST] /openapi/kefustate/change/{TOKEN} 接口。</para>
|
||||
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/thirdkefu/getstate.html </para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Models.OpenApiKefuStateChangeResponse> ExecuteOpenApiKefuStateChangeAsync(this WechatOpenAIClient client, Models.OpenApiKefuStateChangeRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (request is null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
IFlurlRequest flurlReq = client
|
||||
.CreateRequest(request, HttpMethod.Post, "openapi", "kefustate", "change", client.Credentials.PushToken!);
|
||||
|
||||
return await client.SendRequestWithJsonAsync<Models.OpenApiKefuStateChangeResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /openapi/kefustate/change/{TOKEN} 接口的请求。</para>
|
||||
/// </summary>
|
||||
[XmlRoot("xml")]
|
||||
public class OpenApiKefuStateChangeRequest : WechatOpenAIRequestEncryptedXmlable
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置用户的 OpenId。
|
||||
/// </summary>
|
||||
[XmlElement("openid")]
|
||||
public string OpenId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置客服接入状态。
|
||||
/// </summary>
|
||||
[XmlElement("kefustate")]
|
||||
public string State { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置有效期(单位:秒)。
|
||||
/// <para>默认值:1800</para>
|
||||
/// </summary>
|
||||
[XmlElement("expires")]
|
||||
public int ExpiresIn { get; set; } = 1800;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /openapi/kefustate/change/{TOKEN} 接口的响应。</para>
|
||||
/// </summary>
|
||||
public class OpenApiKefuStateChangeResponse : WechatOpenAIResponse
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /openapi/kefustate/get/{TOKEN} 接口的请求。</para>
|
||||
/// </summary>
|
||||
[XmlRoot("xml")]
|
||||
public class OpenApiKefuStateGetRequest : WechatOpenAIRequestEncryptedXmlable
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置用户的 OpenId。
|
||||
/// </summary>
|
||||
[XmlElement("openid")]
|
||||
public string OpenId { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /openapi/kefustate/get/{TOKEN} 接口的响应。</para>
|
||||
/// </summary>
|
||||
public class OpenApiKefuStateGetResponse : WechatOpenAIResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置客户接入状态。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("kefustate")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("kefustate")]
|
||||
public string State { get; set; } = default!;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /openapi/sendmsg/{TOKEN} 接口的请求。</para>
|
||||
/// </summary>
|
||||
[XmlRoot("xml")]
|
||||
public class OpenApiSendMessageRequest : WechatOpenAIRequestEncryptedXmlable
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置用户的 OpenId。
|
||||
/// </summary>
|
||||
[XmlElement("openid")]
|
||||
public string OpenId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置消息内容。
|
||||
/// </summary>
|
||||
[XmlElement("msg")]
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置渠道。
|
||||
/// </summary>
|
||||
[XmlElement("channel")]
|
||||
public int Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置事件。
|
||||
/// </summary>
|
||||
[XmlElement("event")]
|
||||
public string? Event { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置客服人员的昵称。
|
||||
/// </summary>
|
||||
[XmlElement("kefuname")]
|
||||
public string? KfName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置客服人员的头像 URL。
|
||||
/// </summary>
|
||||
[XmlElement("kefuavatar")]
|
||||
public string? KfAvatarUrl { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /openapi/sendmsg/{TOKEN} 接口的响应。</para>
|
||||
/// </summary>
|
||||
public class OpenApiSendMessageResponse : WechatOpenAIResponse
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
|
||||
{
|
||||
internal static class XmlUtility
|
||||
{
|
||||
public static string Serialize(Type type, object obj)
|
||||
{
|
||||
string xml;
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = new System.Xml.XmlTextWriter(stream, Encoding.UTF8);
|
||||
writer.Formatting = System.Xml.Formatting.None;
|
||||
|
||||
XmlSerializer xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
|
||||
XmlSerializerNamespaces xmlNamespace = new XmlSerializerNamespaces();
|
||||
xmlNamespace.Add(string.Empty, string.Empty);
|
||||
xmlSerializer.Serialize(writer, obj, xmlNamespace);
|
||||
writer.Flush();
|
||||
xml = Encoding.UTF8.GetString(stream.ToArray());
|
||||
xml = Regex.Replace(xml, "\\s+<\\w+ (xsi|d2p1):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
|
||||
xml = Regex.Replace(xml, "<\\?xml[^>]*\\?>", string.Empty, RegexOptions.IgnoreCase);
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
public static string Serialize<T>(T obj)
|
||||
where T : class
|
||||
{
|
||||
return Serialize(typeof(T), obj);
|
||||
}
|
||||
}
|
||||
}
|
@ -112,6 +112,15 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
{
|
||||
try
|
||||
{
|
||||
if (data is WechatOpenAIRequestEncryptedXmlable xmlData)
|
||||
{
|
||||
if (xmlData.AppId == null)
|
||||
xmlData.AppId = Credentials.AppId;
|
||||
|
||||
string xml = Utilities.XmlUtility.Serialize(xmlData);
|
||||
data = new { encrypt = Utilities.WxBizMsgCryptor.AESEncrypt(plainText: xml, encodingAESKey: Credentials.PushEncodingAESKey!, appId: xmlData.AppId!) };
|
||||
}
|
||||
|
||||
using IFlurlResponse flurlResponse = await base.SendRequestWithJsonAsync(flurlRequest, data, cancellationToken).ConfigureAwait(false);
|
||||
return await GetResposneAsync<T>(flurlResponse).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[System.Xml.Serialization.XmlIgnore]
|
||||
[System.Xml.Serialization.SoapIgnore]
|
||||
public virtual int? Timeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -19,6 +21,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[System.Xml.Serialization.XmlIgnore]
|
||||
[System.Xml.Serialization.SoapIgnore]
|
||||
public virtual string? RequestId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -26,6 +30,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[System.Xml.Serialization.XmlIgnore]
|
||||
[System.Xml.Serialization.SoapIgnore]
|
||||
public virtual string? BotId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -33,6 +39,17 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[System.Xml.Serialization.XmlIgnore]
|
||||
[System.Xml.Serialization.SoapIgnore]
|
||||
public virtual string? AccessToken { get; set; }
|
||||
}
|
||||
|
||||
public abstract class WechatOpenAIRequestEncryptedXmlable : WechatOpenAIRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置微信 AppId。如果不指定将使用构造 <see cref="WechatOpenAIClient"/> 时的 <see cref="WechatOpenAIClientOptions.AppId"/> 参数。
|
||||
/// </summary>
|
||||
[System.Xml.Serialization.XmlElement("appid")]
|
||||
public string? AppId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -32,16 +32,30 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
/// <summary>
|
||||
/// 获取微信智能对话 API 返回的错误码。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("code")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("code")]
|
||||
public virtual int ErrorCode { get; set; }
|
||||
[Newtonsoft.Json.JsonProperty("errcode")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("errcode")]
|
||||
public virtual int? ErrorCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信智能对话 API 返回的错误描述。
|
||||
/// 获取微信智能对话 API 返回的错误信息。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("errmsg")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("errmsg")]
|
||||
public virtual string? ErrorMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信智能对话 API 返回的状态码。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("code")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("code")]
|
||||
public virtual int? Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信智能对话 API 返回的调用信息。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("msg")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("msg")]
|
||||
public virtual string? ErrorMessage { get; set; }
|
||||
public virtual string? Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信智能对话 API 返回的请求唯一标识。
|
||||
@ -51,12 +65,12 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
|
||||
public virtual string? RequestId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,该值指示调用微信 API 是否成功(即 HTTP 状态码为 200、且 errcode 值为 0)。
|
||||
/// 获取一个值,该值指示调用微信 API 是否成功(即 HTTP 状态码为 200、且 code 和 errcode 值都为 0)。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool IsSuccessful()
|
||||
{
|
||||
return RawStatus == 200 && ErrorCode == 0;
|
||||
return RawStatus == 200 && ErrorCode.GetValueOrDefault() == 0 && Code.GetValueOrDefault() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat
|
||||
namespace SKIT.FlurlHttpClient.Wechat
|
||||
{
|
||||
/// <summary>
|
||||
/// SKIT.FlurlHttpClient.Wechat 请求接口。
|
||||
|
@ -1,16 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat
|
||||
namespace SKIT.FlurlHttpClient.Wechat
|
||||
{
|
||||
/// <summary>
|
||||
/// SKIT.FlurlHttpClient.Wechat 响应接口。
|
||||
/// </summary>
|
||||
public interface IWechatResponse : ICommonResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取微信 API 返回的错误描述。
|
||||
/// </summary>
|
||||
string? ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
<xml>
|
||||
<userid>用户的唯一ID,(通常为用户在微信的openid)</userid>
|
||||
<appid>应用的appid</appid>
|
||||
<content>
|
||||
<msg>机器人或用户的的内容</msg>
|
||||
</content>
|
||||
<event>userEnter</event>
|
||||
<from>0</from>
|
||||
<status>0</status>
|
||||
<channel>渠0</channel>
|
||||
<assessment>0</assessment>
|
||||
<createtime>1234567890</createtime>
|
||||
</xml>
|
@ -0,0 +1,10 @@
|
||||
<xml>
|
||||
<userid>用户的唯一ID,(通常为用户在微信的openid)</userid>
|
||||
<appid>应用的appid</appid>
|
||||
<event>userQuit</event>
|
||||
<from>0</from>
|
||||
<status>0</status>
|
||||
<channel>渠0</channel>
|
||||
<assessment>0</assessment>
|
||||
<createtime>1234567890</createtime>
|
||||
</xml>
|
@ -11,6 +11,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="ModelSamples/**/*.json" />
|
||||
<Content Include="EventSamples/**/*.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user