DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: forget66
今日帖子: 61
在线用户: 14
导航: 论坛 -> 文档资料 斑竹:liumazi,ruralboy  
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:32:49
标题:
Delphi/QuickBurro微信接口组件介绍 浏览:9046
加入我的收藏
楼主: 一、接口概况
    通过在QuickBurro中间件上扩展一个Web插件,就可以实现与微信公众平台之间的接口,一方面将你的应用业务展现到微信客户端,另一方面又将微信客户端的客户需求和消息接入到你的应用系统中。而在此接口实现时,将业务逻辑以调用外部应用程序员编写的dll模块进行实现后,又可以将接口部分封装固化起来而同时又不失应用开发的灵活度;另外,以Delphi控件的形式向VCL桌面程序或Firemonkey移动客户端提供接口,又可以让应用程序员轻易地实现在应用程序里集成微信消息收发处理功能。

    通过两周的潜心设计开发,咱实现了上述这一思路,编写完成的weixinservice.dll插件成功部署到了QuickBurro中间件。此控件具体功能如下:
1、应答来自微信平台的公众号接口认证、实现对接
2、接收发送自微信客户端而由微信服务器转发来的消息、完成解析
3、根据预先设置的消息回复策略,向发来消息的微信客户端自动回复消息
4、接收来自微信客户端的事件消息,并进行自动应答及消息转发给QuickBurro客户端
5、对客户服务有效期(默认48小时)内的活动客户进行管理
6、设立针对微信客户服务的客服人员列表并进行动态维护管理
7、接收来自QuickBurro客户端的各种查询、管理、消息回复、群发消息等各种请求,并作出相应服务处理
8、配置自动回复策略数据表,并提供配置管理周边工具
9、配置消息备份数据表,自动实现收发消息的备份
10、提供动态调用外部业务逻辑模块的插件机制,实现对应用程序员编写模块的调用

    下图是QuickBurro微信接口方案示意图:
此帖子包含附件:
PNG 图像
大小:62.7K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:33:33
1楼: 二、接口服务模块部署操作
    微信接口插件weixinservice.dll会在QuickBurro V4.37及后续版本里集成,所以,在应用程序员使用此接口进行应用开发时,只要按如下方法进行配置,即可:

1、部署中间件,并在你的应用数据库里新增两个数据表:
----自动应答配置表
CREATE TABLE WeixinAutoReply(MsgTypeId int, MsgTypeName nvarchar(32),
       Keyword nvarchar(64), ReplyMode int, ReplyContent ntext)

----消息备份数据表
CREATE TABLE WeixinMessages(MsgDirect nvarchar(4),CustomerId nvarchar(36), 
       ServicerId nvarchar(36),MsgType nvarchar(8),SubType nvarchar(12),
       MsgBody ntext,SaveDateTime nvarchar(17))

    再将你的应用数据库注册到中间件。


2、微信公众号申请与接口配置
    在微信公众服务平台https://mp.weixin.qq.com/申请公众号(订阅号、企业号、服务号等),然后,在网页上登录,在“开发中心”-“配置项”里进行服务器配置,完成后进行启用。如下图示。

3、配置server\plugins\common\weixinservoce.sys文件里的微信接口工作参数:
{
      "Token": "quickburroverygood",          // 微信公众号令牌
      "TokenInterval": 60,          // 获取访问令牌的时间周期,默认60分钟
      "EnableMsgBackup": true,          // 是否启用消息备份
      "MsgKeepDays": 7,          // 备份消息保留天数
      "DatabaseId": "testdb",          // 数据库标识代码
      "EnableMsgRelay": true,          // 是否启用自动回复
      "EnableMsgNotice": true,          // 是否启用消息转发
      "AppID": "wx3b4231c88ece96da",          // 公众号应用ID
      "AppSecret": "9726dfb4d8212241d02052348dd",          // 公众号应用密钥
      "CustomServiceHours": 48,          // 客户服务有效期,默认48小时
      "SubscribeTimeout": 300          // 客服人员心跳包周期,默认300秒
   }
    配置完成后保存,重启中间件服务,以生效。
此帖子包含附件:
PNG 图像
大小:29.4K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:34:01
2楼: 三、自动消息回复设置
    可以为你的公众号设置一套自动回复机制,以提高客户服务的质量。在本接口方案里,可以使用作者提供的周边工具进行。你也可以自己对WeixinAutoReply数据表内容进行增删改,以实现配置。下图是自动回复消息配置及微信客户端的使用效果截图:
此帖子包含附件:
PNG 图像
大小:64.8K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:34:27
3楼: 四、应用插件提供回复消息内容
    在设置自动回复时,可以指定回复的消息来自外部dll模块,这时,微信接口插件在回复之前会先调用指定的dll以获得回复内容,然后再进行应答。外部模块的编写方法和quickburro的web插件写法一致,下面是一个示例,以及运行后的效果截图:

//
// 微信接口回复内容供应插件示例
//
library weixinreply;

uses
  Fastmm4,
  SysUtils,
  Classes,
  Windows,
  Provider,
  dbclient,
  AdoDB,
  MIDASLIB,
  AnsiStrings,
  QBParcel,
  DllSpread,
  NodeServiceAPI,
  qbcommon;

{$R *.RES}

//
// 用户编写的主函数...
function MainFunction(InParcel: TQBParcel; OutParcel: TQBParcel): boolean;
var
   transferkey,ThisNodeId,DatabaseId: ansistring;
   ReplyContent: ansistring;
begin
   transferkey:=InParcel.GetAnsiStringGoods('Transfer_Key');
   ThisNodeId:=InParcel.GetAnsiStringGoods('ThisNodeId');
   DatabaseId:=InParcel.GetAnsiStringGoods('DatabaseId');
//
// 回传一条应答消息...
   ReplyContent:='地瓜地瓜,我是土豆,我是土豆!'+#13#10
          +'   transferkey='+transferkey+#13#10
          +'   ThisNodeId='+ThisNodeId+#13#10
          +'   DatabaseId='+DatabaseId+#13#10;
   OutParcel.PutAnsiStringGoods('ReplyContent',ReplyContent);
   result:=true;
end;

//
// 主函数...
function RemoteProcess(InParcelPtr: integer; var OutParcelPtr: integer): boolean; stdcall;
var
   aInParcel: TQBParcel;
   aOutParcel: TQBParcel;
begin
   try
      aInParcel:=TQBParcel(InParcelPtr);
   except
      result:=false;
      exit;
   end;
   aOutParcel:=TQBParcel.Create;
//
// 调用用户编写的任务处理函数...
   Result:=MainFunction(aInParcel,aOutParcel);
//
// 返回...
   if aOutParcel.GoodsCount<=0 then
      OutParcelPtr:=0
   else
      OutParcelPtr:=Parcel2Mem(aOutParcel);
   aOutParcel.free;
end;

//
// 向主程序提供的函数或过程的输出声明...
exports
   RemoteProcess;

//
// 初始化代码...
begin
   ismultithread:=true;
end.
此帖子包含附件:
PNG 图像
大小:47.3K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:34:57
4楼: 五、应用插件异步回复消息
    对于上面的由外部dll提供内容的方式,是由微信接口模块同步调用外部dll模块实现的,一般只用于回复简单的Text、DLL执行过程不会很耗时的场合。相对的,对于那些需要回复不一定是text、执行业务逻辑的时间也可能很长的场合,同步调用就不合适了,为此本接口方案提供了异步调用外部DLL模块的方式。下面的插件示例代码显示如何在外部dll里连接数据库、根据微信客户端输入的职工姓名来查数据表、最终得到工资查询结果的:

//
// 微信接口插件调用异步回复的示例
//
library weixinreply2;

uses
  Fastmm4,
  SysUtils,
  Classes,
  Windows,
  {$IFDEF UNICODE}
  AnsiStrings,
  {$ENDIF}
  AdoDB,
  QBParcel,
  QBJson,
  qbcommon,
  DllSpread,
  NodeServiceAPI,
  xmldom,
  XMLIntf,
  msxmldom,
  XMLDoc,
  WeixinApi;

{$R *.RES}

//
// 用户编写的主函数...
function MainFunction(InParcel: TQBParcel; OutParcel: TQBParcel): boolean;
var
   RawConn: _Connection;
   AdoConn: TAdoConnection;
   AdoDataset: TAdoDataset;
   PoolId,ConnId: integer;
   //
   DatabaseId,AskContent: ansistring;
   OpenId,Content: ansistring;
   //
   xml: IXMLDocument;
   Root: IXMLNode;
begin
//
// 取传入的参数...
   DatabaseId:=InParcel.GetAnsiStringGoods('DatabaseId');
   AskContent:=InParcel.GetAnsiStringGoods('AskContent');
//
// 解析从微信服务器传来的XML,得到发送者、内容...
   try
      XML:=LoadXMLData(string(AskContent));
      Root:=XML.DocumentElement;
      OpenId:=AnsiString(Root.ChildNodes.FindNode('FromUserName').Text);
      Content:=AnsiString(Root.ChildNodes.FindNode('Content').Text);
   except
      result:=false;
      exit;
   end;
   XML:=nil;
//
// 查数据库,得到结果...
   if not GetAdoConnection(InParcel,DatabaseId,adoconn,RawConn,poolid,connid) then
      begin
         SendTextToCustomer(InParcel, OpenId,'服务端出错了:分配数据库连接对象失败!');
         result:=true;
         exit;
      end;
   try
      AdoDataset:=TAdoDataset.Create(nil);
      AdoDataset.DisableControls;
      AdoDataset.CommandTimeout:=60;
      AdoDataset.Connection:=AdoConn;
      AdoDataset.CommandText:='SELECT * FROM Wage WHERE WORKER='''+string(Content)+'''';
      AdoDataset.Active:=true;
      if AdoDataset.RecordCount=0 then
         Content:='不好意思,没查到你的工资记录!'
      else
         Content:='查询成功,你的工资='+ansistring(formatfloat('0.00',AdoDataset.FieldByName('Money').AsFloat));
      AdoDataset.Active:=false;
   except
      Content:='服务端出错了:访问数据库失败!';
   end;
   qbcommon.SafeFreeAdods(AdoDataset);
   FreeAdoConnection(InParcel,AdoConn,RawConn,PoolId,ConnId);
//
// 发送查询结果给微信客户端...
   SendTextToCustomer(InParcel, OpenId,Content);
   result:=true;
end;

//
// 主函数...
function RemoteProcess(InParcelPtr: integer; var OutParcelPtr: integer): boolean; stdcall;
var
   aInParcel: TQBParcel;
   aOutParcel: TQBParcel;
begin
   try
      aInParcel:=TQBParcel(InParcelPtr);
   except
      result:=false;
      exit;
   end;
   aOutParcel:=TQBParcel.Create;
   try
      Result:=MainFunction(aInParcel,aOutParcel);
      if result then
         begin
          if aOutParcel.GoodsCount<=0 then
          OutParcelPtr:=0
          else
          OutParcelPtr:=Parcel2Mem(aOutParcel);
         end;
   except
      result:=false;
   end;
   aOutParcel.free;
end;

//
// 向主程序提供的函数或过程的输出声明...
exports
   RemoteProcess;

//
// 初始化代码...
begin
   ismultithread:=true;
end.
此帖子包含附件:
PNG 图像
大小:40.1K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:35:22
5楼: 六、消息转发
    将微信接口配置参数中的消息转发开关打开,就可以让接口插件在收到来自微信客户端的消息或事件后将它们转发到QuickBurro应用程序的客户端。在QuickBurro客户端,VCL程序里可以用TMsgReceiver控件接收消息,FireMonkey下可用TMBReceiver控件接收消息。下面是消息接收示例代码以及微信客户端和QuickBurro客户端(测试程序)之间进行对话的截图:

//
// VCL程序下,收到来自dll的消息时...
procedure TMainForm.ReceiverCallbackMessage(MsgParcel: TQBParcel; DllFilename: string);
var
   FromCustomerId,MsgType,SubType,MsgBody: ansistring;
begin
   if stricomp(pchar(extractfilename(dllfilename)),'weixinservice.dll')=0 then
      begin
         FromCustomerId:=MsgParcel.GetAnsiStringGoods('FromCustomerId');
         MsgType:=MsgParcel.GetAnsiStringGoods('MsgType');
         SubType:=MsgParcel.GetAnsiStringGoods('SubType');
         MsgBody:=MsgParcel.GetAnsiStringGoods('MsgBody');
         memo2.Lines.Add('');
         memo2.Lines.Add('*** '+formatdatetime('yy-mm-dd hh:nn:ss',now)+' ['+string(FromCustomerId)+']:');
         memo2.Lines.Add(string(MsgBody));
      end;
end;

//
// 手机测试程序里,收到消息时...
procedure TForm1.ReceiverMessageArrives(Sender: TObject; NewMsgCount: Integer);
var
   FromCustomerId,MsgType,SubType,MsgBody: string;
   MsgParcel: TMBParcel;
begin
   while Receiver.PopMessage(MsgParcel) do
      begin
         //
         // 不是来自微信接口的消息,丢弃...
         if lowercase(MsgParcel.GetStringGoods('FromPluginId'))<>'weixinservice.dll' then
          begin
          FreeAndNil(MsgParcel);
          continue;
          end;
         FromCustomerId:=MsgParcel.GetStringGoods('FromCustomerId');
         MsgType:=MsgParcel.GetStringGoods('MsgType');
         SubType:=MsgParcel.GetStringGoods('SubType');
         MsgBody:=MsgParcel.GetStringGoods('MsgBody');
         memo1.Lines.Add('*** 【'+FromCustomerId+'】:');
         memo1.Lines.Add('      '+MsgType+':'+MsgBody);
         FreeAndNil(MsgParcel);
      end;
end;
此帖子包含附件:
PNG 图像
大小:153.0K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:35:50
6楼: 七、应用程序客户端向微信客户端发送消息
    应用程序客户端可以通过此接口向微信客户端群发消息(权限及次数有限制,请查阅微信公众平台资料),也可以向当前处于活动期(48小时)的微信客户端单发各种消息。下面是几段示例代码以及运行效果截图:
//
// 群发文本消息...
procedure TForm1.Button31Click(Sender: TObject);
var
   ok: boolean;
begin
   ok:=false;
   if Radiobutton1.IsChecked then
      ok:=wx.BroadTextToCustomers('国航CA433班机多人打群架');
   if Radiobutton2.IsChecked then
      ok:=wx.BroadTextToCustomers('国航CA433班机多人打群架',0);
   if Radiobutton3.IsChecked then
      ok:=wx.BroadTextToCustomers('国航CA433班机多人打群架',trim(edit6.Text));
   if ok then
      memo1.Lines.Add('群发文本消息到关注者成功!')
   else
      memo1.Lines.Add('群发文本消息到关注者失败!Error='+wx.LastError);
end;

//
// 群发图片消息...
procedure TForm1.Button32Click(Sender: TObject);
var
   ok: boolean;
begin
   ok:=false;
   if Radiobutton1.IsChecked then
      ok:=wx.BroadImageToCustomers(trim(edit1.Text));
   if Radiobutton2.IsChecked then
      ok:=wx.BroadImageToCustomers(trim(edit1.Text),0);
   if Radiobutton3.IsChecked then
      ok:=wx.BroadImageToCustomers(trim(edit1.Text),trim(edit6.Text));
   if ok then
      memo1.Lines.Add('群发图片消息到关注者成功!')
   else
      memo1.Lines.Add('群发图片消息到关注者失败!Error='+wx.LastError);
end;

//
// 群发图文消息...
procedure TForm1.Button35Click(Sender: TObject);
var
   ok: boolean;
begin
   ok:=false;
   if Radiobutton1.IsChecked then
      ok:=wx.BroadMPNewsToCustomers(trim(edit1.Text));
   if Radiobutton2.IsChecked then
      ok:=wx.BroadMPNewsToCustomers(trim(edit1.Text),0);
   if Radiobutton3.IsChecked then
      ok:=wx.BroadMPNewsToCustomers(trim(edit1.Text),trim(edit6.Text));
   if ok then
      memo1.Lines.Add('群发图文消息到关注者成功!')
   else
      memo1.Lines.Add('群发图文消息到关注者失败!Error='+wx.LastError);
end;

//
// 发送文本客服消息...
procedure TForm1.Button25Click(Sender: TObject);
begin
   if wx.SendTextToCustomer(trim(edit4.Text),Edit5.Text) then
      begin
         memo1.Lines.Add(formatdatetime('yy-mm-dd hh:nn:ss',now)+' [我]:');
         memo1.Lines.Add(Edit5.Text);
      end
   else
      memo1.Lines.Add('发送失败!Error:'+wx.LastError);
end;

//
// 发送图片客服消息...
procedure TForm1.Button26Click(Sender: TObject);
begin
   if wx.SendImageToCustomer(trim(edit4.Text),trim(edit1.Text)) then
      begin
         memo1.Lines.Add(formatdatetime('yy-mm-dd hh:nn:ss',now)+' [我]:');
         memo1.Lines.Add('图片<'+trim(edit1.Text)+'>');
      end
   else
      memo1.Lines.Add('发送失败!Error:'+wx.LastError);
end;

//
// 发送图文客服消息...
procedure TForm1.Button30Click(Sender: TObject);
var
   aNews: TNewsRecord;
begin
   wx.ClearNews;
   aNews.title:='关于快驴微信接口的公告';
   aNews.description:='爽歪歪啊爽歪歪,外力格外,歪里个歪。QuickBurro中间件是一款'
      +'Delphi/BCB下的多层分布式应用开发套件,功能强大、品质优良、服务到位。'
      +'爽歪歪哦爽歪歪,歪里个歪。';
   aNews.url:='http://www.quickburro.com/index.html&#39;;
   aNews.picurl:='http://www.quickburro.com/images/small-model1.png&#39;;
   wx.AddNews(aNews);
   if wx.SendNewsToCustomer(trim(edit4.Text)) then
      begin
         memo1.Lines.Add(formatdatetime('yy-mm-dd hh:nn:ss',now)+' [我]:');
         memo1.Lines.Add('<图文消息>');
      end
   else
      memo1.Lines.Add('发送失败!Error:'+wx.LastError);
end;
此帖子包含附件:
PNG 图像
大小:126.2K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/21 10:36:29
7楼: 八、配套应用开发控件
    QuickBurro的VCL开发包、Firemonkey开发包里各带一个客户端应用开发的微信接口控件,用于进行微信接口的各种应用客户端编程,下面是主要方法介绍(以FireMonkey下的TMBWeixin控件为例):
//
// 构造方法...
Constructor Create(AOwner: TComponent); override;
//
// 析构方法...
Destructor Destroy(); override;
//
// 清除图文信息列表缓冲区...
procedure ClearNews;
//
// 增加一条图文消息到缓冲区...
procedure AddNews(aNews: TNewsRecord);
//
// 清除群发用的图文消息缓冲区...
procedure ClearMPNews;
//
// 向群发用的图文消息缓冲区增加一条图文消息...
procedure AddMPNews(aMPNews: TMPNewsRecord);
//
// 取微信服务器地址...
function GetServerList(var IPList: TStringList): boolean;
//
// 上传文件到微信服务器...
function UploadFile(const FileType: string; const FileName: string; var MediaId: string): boolean;
//
// 从微信服务器下载文件...
function DownloadFile(const MediaId: string; const FileName: string): boolean;
//
// 上传群发用的图文信息到微信服务器...
function UploadMPNews(var MediaId: string): boolean;
//
// 上传视频信息到微信服务器...
function UploadVideo(const title: string; const desc: string; const ThumbMediaId: string; var MediaId: string): boolean;
//
// 取公众号所有关注者列表...
function FetchCustomerList(var OpenIdList: TStringList): boolean;
//
// 取指定客户的属性...
function GetCustomerInfo(const OpenId: string; var CustInfo: TCustomerRecord; const Language: string='zh_CN'): boolean;
//
// 设置客户备注...
function SetCustomerDesc(const OpenId: string; const CustomerDesc: string): boolean;
//
// 取活动期客户列表...
function FetchActiveCustomerList(): boolean;
//
// 取公众号客户分组列表...
function FetchGroupList(): boolean;
//
// 创建客户分组...
function CreateGroup(const GroupName: string; var GroupId: integer): boolean;
//
// 客户分组重命名...
function RenameGroup(const GroupId: integer; const NewGroupName: string): boolean;
//
// 取客户所在分组号...
function GetCustomerGroup(const OpenId: string; var GroupId: integer): boolean;
//
// 改换客户所在分组...
function ChangeCustomerGroup(const OpenId: string; const NewGrpupId: integer): boolean;
//
// 取客服人员列表...
function FetchServicerList(): boolean;
//
// 增加一个客服人员...
function AddServicer(const MyName: string): boolean;
//
// 删除一个客服人员...
function RemoveServicer(): boolean;
//
// 开始为一个活动客户进行服务...
function BeginService(const OpenId: string; const MyName: string): boolean;
//
// 停止对某个客户的服务...
function StopService(const OpenId: string): boolean;
//
// 判断当前连接是否是客服身份...
function IsServicer(): boolean;
//
// 取当前正在客服的客户...
function ServicingCustomerId(): string;
//
// 发送文本客服消息...
function SendTextToCustomer(const OpenId: string; const TextContent: string): boolean;
//
// 发送图片客服消息...
function SendImageToCustomer(const OpenId: string; const ImageMediaId: string): boolean;
//
// 发送语音客服消息...
function SendVoiceToCustomer(const OpenId: string; const VoiceMediaId: string): boolean;
//
// 发送视频客服消息...
function SendVideoToCustomer(const OpenId: string; const VideoMediaId: string;
    const ThumbMediaId: string; const title: string; const Desc: string): boolean;
//
// 发送音乐客服消息...
function SendMusicToCustomer(const OpenId: string; const MusicUrl: string;
   const HQMusicUrl: string; const ThumbMediaId: string; const title: string; const Desc: string): boolean;
//
// 发送图文客服消息...
function SendNewsToCustomer(const OpenId: string): boolean;
//
// 群发文本消息...
function BroadTextToCustomers(const TextContent: string): boolean; overload;
function BroadTextToCustomers(const TextContent: string; const GroupId: integer): boolean; overload;
function BroadTextToCustomers(const TextContent: string; const OpenIdList: string): boolean; overload;
//
// 群发图片消息...
function BroadImageToCustomers(const ImageMediaId: string): boolean; overload;
function BroadImageToCustomers(const ImageMediaId: string; const GroupId: integer): boolean; overload;
function BroadImageToCustomers(const ImageMediaId: string; const OpenIdList: string): boolean; overload;
//
// 群发语音消息...
function BroadVoiceToCustomers(const VoiceMediaId: string): boolean; overload;
function BroadVoiceToCustomers(const VoiceMediaId: string; const GroupId: integer): boolean; overload;
function BroadVoiceToCustomers(const VoiceMediaId: string; const OpenIdList: string): boolean; overload;
//
// 群发视频消息...
function BroadVideoToCustomers(const VideoMediaId: string): boolean; overload;
function BroadVideoToCustomers(const VideoMediaId: string; const GroupId: integer): boolean; overload;
function BroadVideoToCustomers(const VideoMediaId: string; const OpenIdList: string): boolean; overload;
//
// 群发图文消息...
function BroadMPNewsToCustomers(const MPNewsMediaId: string): boolean; overload;
function BroadMPNewsToCustomers(const MPNewsMediaId: string; const GroupId: integer): boolean; overload;
function BroadMPNewsToCustomers(const MPNewsMediaId: string; const OpenIdList: string): boolean; overload;
//
// 取最后一次错误的错误信息...
function LastError(): string;


九、后记
    微信公众号接口受制于公众号的类别、是否认证等因素,所以有时有些功能调用失败是正常的,请查阅公众平台说明资料。而某些敏感或负荷大的功能也可能暂时调用失败,出现系统忙之类的错误应答,也是正常的。总的来说,无论微信公众号平台,还是我们的接口模块,都处于发展中,相信明天会更好!
----------------------------------------------
樵夫的大马甲
作者:
男 lqgvt (lqgvt) ★☆☆☆☆ -
盒子活跃会员
2014/12/21 10:46:44
8楼: 这速度,一个字  顶
----------------------------------------------
人世间,无所谓爱,无所谓情!只是人们叫得多了才有了爱情!
作者:
男 hbug (hbug) ★☆☆☆☆ -
普通会员
2014/12/21 11:33:10
9楼: 有没有微信支付的接口?
----------------------------------------------
专业提供人力资源软件、指纹考勤软件、POS进销存软件、酒店餐饮软件
http://www.winsoftcn.com
作者:
男 hyz_hz (随风) ★☆☆☆☆ -
普通会员
2014/12/21 15:51:40
10楼: 终于出来了,顶一下,同样期待微信支付接口.
----------------------------------------------
-
作者:
男 delphicrack (delphicrack) ★☆☆☆☆ -
盒子活跃会员
2014/12/21 20:22:26
11楼: 想咨询一下,个人买是不是可以半价?
----------------------------------------------
-
作者:
男 epzybook (epzybook) ★☆☆☆☆ -
普通会员
2014/12/21 21:18:33
12楼: 请问怎么收费?
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/12/21 21:27:07
13楼: 牛逼的
----------------------------------------------
-
作者:
男 axfx (axfx) ▲▲▲▲▲ -
普通会员
2014/12/22 8:45:03
14楼: 很好 ,一直关注中。。。
----------------------------------------------
超低价出售pos/进销存/收银软件源码
https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.4fee645eC26dvB&ft=t&id=671027238807
作者:
男 brh616 (风风风) ★☆☆☆☆ -
盒子活跃会员
2014/12/22 9:09:18
15楼: 绝对的强大!
支持!
----------------------------------------------
风风风
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/22 12:21:02
16楼: 来啦,谢谢各位支持!
目前是元旦促销期,一律5折
----------------------------------------------
樵夫的大马甲
作者:
男 bhhgd (bhhgd) ★☆☆☆☆ -
普通会员
2014/12/22 19:32:08
17楼: 好牛逼的樵夫,奔5的人了还有那么旺盛精力去研究这研究那
----------------------------------------------
-
作者:
男 roker (roker) ★☆☆☆☆ -
盒子活跃会员
2014/12/23 4:33:29
18楼: 膜拜樵帮主。。。。
----------------------------------------------
-
作者:
男 chinahth (淡若浮云) ★☆☆☆☆ -
盒子活跃会员
2014/12/23 12:37:39
19楼: 登录来支持,不错,期待支付接口
----------------------------------------------
-
作者:
男 yam (yam) ★☆☆☆☆ -
盒子活跃会员
2014/12/23 14:54:05
20楼: 感觉把这个做成delphi版的微信中间件来卖,只要公众号的功能都能实现,卖的肯定比集成到驴里多
----------------------------------------------
-
作者:
男 drroc (mvcxe) ★☆☆☆☆ -
盒子活跃会员
2014/12/23 16:55:34
21楼: 微信接口都是开放的,楼上还想着封起来卖钱,呵呵
----------------------------------------------
MVCXE中国首个DELPHI MVC WEB框架:https://www.mvcxe.com/
作者:
男 yam (yam) ★☆☆☆☆ -
盒子活跃会员
2014/12/25 8:28:46
22楼: 微信公开的接口方法都是非delphi的,如果有了个delphi的解决方案,肯定很多人会开心,当然成本不高才合适。
樵夫一直都为大家提供免费的方案,做个收费的相信有很多朋友支持。
----------------------------------------------
-
作者:
男 fky1989 (fky1989) ▲▲▲▲▲ -
普通会员
2014/12/25 9:59:26
23楼: 樵夫加油。
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/25 11:10:39
24楼: @22楼: 你说反了,咱一直做收费的。免费的,弄得不多。
本帖所说的方案,已经实现并发布了,请下载QuickBurro V4.37试用。
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/25 11:21:16
25楼: 由于微信公众号接口需要Web服务器支持,所以,各位所说的“单独做”其实并不是个好主意:

1、单独顺便做一个Web服务器?
2、怎么和其他应用紧密集成?

集成到中间件里,是最合适的,因为不仅Web服务问题解决,和你的三层架构应用软件也可紧密接口,更有大量的三层架构现成的中间层及客户端功能(比如数据库连接池、消息传输服务、文件传输服务等)可供调用。  我不相信,单独做了,这些你都能轻松搞定。
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/25 17:31:42
26楼: 近日,又完成了微信企业号的对接,再过几天,就可以做出Delphi版的企业号接口开发控件。 下图是企业号的对接测试,同样由后台QuickBurro微信接口服务插件提供服务:
此帖子包含附件:
JPEG 图像
大小:33.2K
----------------------------------------------
樵夫的大马甲
作者:
男 xxhadsg (garfield) ★☆☆☆☆ -
盒子活跃会员
2014/12/29 10:08:36
27楼: 很好很强大
----------------------------------------------
这个世界上还有很多比钱更重要的东西,比如说意大利面---加菲猫
作者:
男 zengxa (zengxa) ★☆☆☆☆ -
普通会员
2014/12/29 14:33:52
28楼: 樵夫非常牛,能考虑支持易信么,呵呵
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2014/12/29 19:35:22
29楼: 易信暂不支持,拣重要的做。

下面,是应用程序员写插件,向微信客户端返回图文信息的示例:

//
// 微信接口图文消息自动应答插件示例
//
library weixinreply1;

uses
  Fastmm4,
  SysUtils,
  Classes,
  Windows,
  AnsiStrings,
  QBParcel,
  DllSpread,
  NodeServiceAPI,
  QBJson,
  qbcommon;

{$R *.RES}

//
// 用户编写的主函数...
function MainFunction(InParcel: TQBParcel; OutParcel: TQBParcel): boolean;
var
   Json,Json1: TQBJson;
   Ja: TQBJsonArray;
begin
//
// 回传图文应答消息...
   Json:=TQBJson.Create;
   Ja:=TQBJsonArray.create;
   //
   json1:=TQBJson.Create;
   json1.Put('title','强大的功能助你高效应用开发!');
   json1.Put('description','几十个控件,功能多多,啥都支持。');
   json1.Put('url','http://www.quickburro.com/functions.html');
   json1.Put('picurl','http://www.quickburro.com/images/small-model2.png');
   ja.put(json1);
   //
   json1:=TQBJson.Create;
   json1.Put('title','丰富的案例是最有说服力的印证!');
   json1.Put('description','几百家客户、大量的应用案例。');
   json1.Put('url','http://www.quickburro.com/Models.html');
   json1.Put('picurl','http://www.quickburro.com/images/small-model30.png');
   ja.put(json1);
   //
   json1:=TQBJson.Create;
   json1.Put('title','免费下载试用不满意可以不花钱!');
   json1.Put('description','满意了再买,不好就不买。');
   json1.Put('url','http://www.quickburro.com/Downloads.html');
   json1.Put('picurl','http://www.quickburro.com/images/small-model3.png');
   ja.put(json1);
   //
   json1:=TQBJson.Create;
   json1.Put('title','买就送多套实用源码、超值!');
   json1.Put('description','好多三层开发技巧方法,源码里可找到。');
   json1.Put('url','http://www.quickburro.com/Orders.html');
   json1.Put('picurl','http://www.quickburro.com/images/small-model4.png');
   ja.put(json1);
   //
   json1:=TQBJson.Create;
   json1.Put('title','作者提供技术咨询、无后顾之忧!');
   json1.Put('description','你问俺答、包你解决疑难问题。');
   json1.Put('url','http://www.quickburro.com/index.html');
   json1.Put('picurl','http://www.quickburro.com/images/small-model1.png');
   ja.put(json1);
   //
   Json.Put('Articles',ja);
   OutParcel.PutIntegerGoods('ReplyType',5);
   OutParcel.PutAnsiStringGoods('Articles',Json.ToString2(2));
   FreeAndNil(Json);
   result:=true;
end;

//
// 主函数...
function RemoteProcess(InParcelPtr: integer; var OutParcelPtr: integer): boolean; stdcall;
var
   aInParcel: TQBParcel;
   aOutParcel: TQBParcel;
begin
   try
      aInParcel:=TQBParcel(InParcelPtr);
   except
      result:=false;
      exit;
   end;
   aOutParcel:=TQBParcel.Create;
//
// 调用用户编写的任务处理函数...
   Result:=MainFunction(aInParcel,aOutParcel);
//
// 返回...
   if aOutParcel.GoodsCount<=0 then
      OutParcelPtr:=0
   else
      OutParcelPtr:=Parcel2Mem(aOutParcel);
   aOutParcel.free;
end;

//
// 向主程序提供的函数或过程的输出声明...
exports
   RemoteProcess;

//
// 初始化代码...
begin
   ismultithread:=true;
end.
此帖子包含附件:
JPEG 图像
大小:33.8K
----------------------------------------------
樵夫的大马甲
作者:
女 yuki11111111 (yuki) ★☆☆☆☆ -
普通会员
2015/1/4 14:23:16
30楼: LZ 你这个控件有没有卖啊? 你网站上面  http://www.quickburro.com/ 是不是这里啊

但是没有微信平台这个方面的啊??请告知
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/1/4 15:45:15
31楼: 下载qbcn.rar或qben.rar(英文界面),
里面带这个接口及应用开发控件

可加群18594635,咨询或讨论
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/1/7 16:35:38
32楼: 下面给出一个QuickBurro客户正在进行的实际应用项目截图,后台业务逻辑部件使用C++ Builder编写(与Delphi编写的接口一致):
此帖子包含附件:
JPEG 图像
大小:97.4K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/4/16 2:28:22
33楼: 今天发布了新版,
增强微信公众号接口
==========

1、增加微信公众号Js-sdk接口支持
2、增加应用页面读取访问者微信号功能(OAuth2验证接口)
3、微信异步调用插件消息应答由回调改为非回调实现
4、简化微信接口Api单元里的函数(去掉底层SSL通信)、增补新的函数
5、修改了原来的几个微信接口Demo、增加了几个新的微信接口Demo
6、对《QuickBurro微信公众号接口应用开发指南》资料的修改和增补内容
---------- 
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/4/16 7:51:48
34楼: 相关资料目录:(下载解包中间件就有)

《QuickBurro微信公众号接口应用开发指南》
      目    录

一、引言
1.1. 公众号接口服务目标
1.2. 公众号接口总体架构
1.3. 应用开发步骤与要点

二、订阅号/服务号接口 
2.1. 订阅号/服务号接口配置与管理 
2.1.1. 申请订阅号/服务号及认证
2.1.2. 部署中间件及订阅号/服务号接口
2.1.3. 配置自动应答消息
2.1.4. 配备客服体系
2.1.5. 微信公众号营销

2.2. 查询关注者信息
2.2.1. 获取关注者列表
2.2.2. 获取关注者详情

2.3. 活动客户管理
2.3.1. 获取活动客户列表
2.3.2. 获取客户活动状态

2.4. 客户分组管理
2.4.1. 取客户分组列表
2.4.2. 增加客户分组 
2.4.3. 分组重命名 
2.4.4. 设定客户所属分组 

2.5. 自定义菜单管理
2.5.1. 创建自定义菜单 
2.5.2. 删除自定义菜单 
2.5.3. 取自定义菜单内容

2.6. 客服人员管理
2.6.1. 获取客服人员列表
2.6.2. 注册为客服人员
2.6.3. 注销客服人员

2.7. 客服消息收发
2.7.1. 客服人员的消息接收
2.7.2. 发送客服消息

2.8. 消息群发
2.8.1. 向所有关注者群发
2.8.2. 向客户分组群发
2.8.3. 向客户Id列表群发

2.9. 同步服务插件编写
2.9.1. 同步服务插件模板
2.9.2. 插件接口参数约定
2.9.3. 一个同步服务插件实例

2.10. 异步业务逻辑部件编写
2.10.1. 异步业务逻辑部件的接口参数约定
2.10.2. API单元回调函数介绍
2.10.3. 一个异步服务插件实例

三、企业号接口
3.1. 企业号接口配置与管理
3.1.1. 微信企业号申请与认证
3.1.2. 部署中间件及微信企业号接口
3.1.3. 配置自动应答消息
3.1.4. 配备管理员统一管理

3.2. 部门管理
3.2.1. 获取部门列表
3.2.2. 新增部门
3.2.3. 修改部门
3.2.4. 注销部门

3.3. 成员管理
3.3.1. 获取部门成员列表
3.3.2. 注册部门成员
3.3.3. 修改部门成员
3.3.4. 删除部门成员

3.4. 标签管理
3.4.1. 获取标签列表
3.4.2. 新增标签
3.4.3. 修改标签
3.4.4. 删除标签
3.4.5. 标签成员管理

3.5. 自定义菜单管理
3.5.1. 创建自定义菜单
3.5.2. 删除自定义菜单
3.5.3. 获取自定义菜单内容

3.6. 消息收发
3.6.1. 管理端接收企业号消息
3.6.2. 向企业号成员发送消息

3.7. 企业号服务插件编写
3.7.1. 企业号服务插件接口说明
3.7.2. API接口单元回调函数说明
3.7.3. 一个企业号服务插件示例

四、四、公众号应用页面编写
4.1. 通过菜单链接应用页面
4.2. 动态页面的编程实现
4.3. 微信JSSDK接口的实现
4.4. 应用页面上获取微信客户端Id

五、结束语
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/4/16 7:55:37
35楼:     微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫等微信特有的能力,为微信用户提供更优质的网页体验。 

    订阅号/服务号的Web插件里,具体调用weixinapi.pas单元中的如下函数,获取步骤二中的JSSDK签名信息:
function GetJsapiInterface(const RequestParcel: TQBParcel; const AppId: ansistring;
   var Noncestr: ansistring; var TimeStamp: ansistring;
   var Signature: ansistring; var Error: ansistring): boolean;
其中:RequestParcel:传入参数,Web插件入口参数包对象
      AppId:传入参数,订阅号/服务号的微信公众号Id
      Noncestr:返回参数,接口验证需要的随机串
      TimeStamp:返回参数,接口验证需要的时间戳串
      Signature:返回参数,接口验证需要的签名串
      Error:当函数失败返回的错误信息

    微信企业号的Web插件里,具体调用weixinentapi.pas单元中的如下函数,获取步骤二中的JSSDK签名信息:
function GetEntJsapiInterface(const RequestParcel: TQBParcel; const CorpId: ansistring;
   const AgentId: integer; var Noncestr: ansistring; var TimeStamp: ansistring;
   var Signature: ansistring; var Error: ansistring): boolean;
其中:RequestParcel:传入参数,Web插件入口参数包对象
      CorpId:传入参数,企业Id
      AgentId:传入参数,企业应用编号
      Noncestr:返回参数,接口验证需要的随机串
      TimeStamp:返回参数,接口验证需要的时间戳串
      Signature:返回参数,接口验证需要的签名串
      Error:当函数失败返回的错误信息


案例:动态生成支持微信JSSDK接口的Web页面(源码节选)
//
// 主函数...
function MainFunction(RequestParcel: TQBParcel; ResponseParcel: TQBParcel): boolean;
var
   tmpfilename,ResponseBody: AnsiString;     {定义若干局部变量}
   NonceStr,TimeStamp,Signature,Error: ansistring;
   j: integer;
   //
   Stream: TMemoryStream;
   LogMsg: TLogMsg;
begin
   LogMsg:=Get_LogMsg(RequestParcel);
//
// 确定模板文件名...
   tmpfilename:=extractfilepath(RequestParcel.GetAnsiStringGoods('Dll_Filename'));
   tmpfilename:=ansistring(GetAbsolutePath(string(tmpfilename),'..\'))+'templates\weixinjssdk.qtml';
   if not fileexists(string(tmpfilename)) then
      begin
         LogMsg(PAnsiChar('weixinjssdk.dll: 模板文件丢失:'+tmpfilename));
         result:=false;
         exit;
      end;
//
// 读取模板内容...
   Stream:=TMemoryStream.Create;
   try
      Stream.LoadFromFile(string(tmpfilename));
      SetLength(ResponseBody,Stream.Size);
      Stream.Position:=0;
      Stream.Read(ResponseBody[1],Stream.Size);
      result:=true;
   except
      result:=false;
   end;
   FreeAndNil(Stream);
   if not result then
      begin
         LogMsg('weixinjssdk.dll: 读取模板文件失败!');
         result:=false;
         exit;
      end;
//
// 调用回调函数得到JsSDK接口参数...
   if not GetJsapiInterface(RequestParcel,'wx17b64980fdda6da0',NonceStr,TimeStamp,Signature,Error) then
      begin
         LogMsg(PAnsiChar('weixinjssdk.dll: 取JSSDK接口参数失败!Error='+error));
         result:=false;
         exit;
      end;
   //
   j:=pos(ansistring('`公众号`'),ResponseBody);
   delete(ResponseBody,j,8);
   insert('wx17b64980fdda6da0',ResponseBody,j);
   //
   j:=pos(ansistring('`时间戳`'),ResponseBody);
   delete(ResponseBody,j,8);
   insert(TimeStamp,ResponseBody,j);
   //
   j:=pos(ansistring('`随机串`'),ResponseBody);
   delete(ResponseBody,j,8);
   insert(NonceStr,ResponseBody,j);
   //
   j:=pos(ansistring('`签名串`'),ResponseBody);
   delete(ResponseBody,j,8);
   insert(Signature,ResponseBody,j);
   //
   try
      ResponseBody:=UTF8Encode(string(ResponseBody));
      ResponseParcel.PutAnsiStringGoods('ResponseBody',ResponseBody);
      ResponseParcel.PutBooleanGoods('DisableGZip',true);  {这样可以控制是否强制不压缩}
   except
      LogMsg(PAnsiChar('weixinjssdk.dll: 保存应答结果失败!'));
   end;
end;

运行效果如下:
此帖子包含附件:
PNG 图像
大小:133.5K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/4/16 7:57:16
36楼:     当通过微信公众号访问你设计的应用页面时,您肯定想获得访问者的微信号以鉴别身份之用,如何实现呢? 答案是通过腾讯提供的“OAuth2验证接口”。为了编程方便,本人在微信接口插件内进行了封装实现,并以weixinapi.pas里的函数形式提供给您(订阅号/服务号):
function GetOpenId(const RequestParcel: TQBParcel; const AppId: ansistring; 
    var OpenId: ansistring): boolean;
其中:RequestParcel:传入参数,Web插件的传入参数包对象
      AppId:传入参数,公众号Id
      OpenId:返回的参数,也就是你希望得到的访问者微信号

    在企业号接口下开发应用页面时,可以通过weixinetapi.pas里的如下方法获取访问者的UserId及DeviceId:
function GetUserId(const RequestParcel: TQBParcel; const CorpId: ansistring;
   const AgentId: integer; var UserId: ansistring; var DeviceId: ansistring): boolean;
其中:RequestParcel:传入参数,Web插件的传入参数包对象
      CorpId:传入参数,企业Id
      AgentId:传入参数,企业应用编号
      UserId:返回的参数,也就是你希望得到的访问者用户号
      DeviceId:返回的参数,也就是你希望得到的访问者设备Id

    下面给出订阅号/服务号下的获取访问者微信号的示例插件代码:
//
// 主函数...
function MainFunction(RequestParcel: TQBParcel; ResponseParcel: TQBParcel): boolean;
var
   OpenId: ansistring;
   ResponseBody: ansistring;
   LogMsg: TLogMsg;
begin
   LogMsg:=Get_LogMsg(RequestParcel);
//
// 调用函数,获得...
   if GetOpenId(RequestParcel,'wx17b64980fdda6da0',OpenId) then
      begin
         ResponseBody:='<html><head><title>获取Openid成功!</title></head>'+#13#10
          +'<body><br><br><br><h1><center>应用页面上获取微信客户端Id成功!<br>OpenId='+OpenId+'</center></h1></body></html>';
         try
          ResponseParcel.PutAnsiStringGoods('ResponseBody',ResponseBody);
          ResponseParcel.PutBooleanGoods('DisableGZip',true);
          result:=true;
         except
          LogMsg('wxgetopenid.dll:返回应答结果失败!');
          result:=false;
         end;
      end
//
// 失败...
   else
      begin
         LogMsg(PAnsiChar('wxgetopenid.dll:调用GetOpenId失败,无法获取OpenId!'));
         result:=false;
      end;
end;
此帖子包含附件:
PNG 图像
大小:11.3K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/4/26 22:50:15
37楼: QuickBurro V4.39 Update7
再次优化、改进此接口,以实现实用化

1、解决了微信公众号接口因每天允许的取关注者列表次数少而引发的问题
2、使用数据表来缓存关注者信息,满足有大量关注者的公众号的需要
3、新增预加载插件的即时加载功能,解决了多公众号公用中间件时的重启服务会互相影响的问题
4、wxmanager工具新增预加载配置管理功能、分页方式取关注者列表、缓存表创建等功能
5、微信公众号API单元新增新的消息传输方法,方便插件编写
----------------------------------------------
樵夫的大马甲
作者:
男 edwinyeah (Edwin) ★☆☆☆☆ -
盒子活跃会员
2015/4/26 23:16:06
38楼: 请问能读取微信服务器的聊天历史记录吗?(我也不确定微信服务器是否有保存完整的记录)。
----------------------------------------------
-
作者:
男 hyz_hz (随风) ★☆☆☆☆ -
普通会员
2015/4/26 23:32:51
39楼: 你是要获取公众号跟微信用户的聊天记录吗?
----------------------------------------------
-
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2015/4/27 19:56:03
40楼: QuickBurro V4.39 Update8

1、开始支持菜单Click消息按不同key值设置自动回复或与插件绑定
2、开始支持Event消息按不同类别设置自动回复及与插件绑定
3、修正获取自动回复参数算法上的小缺陷
----------------------------------------------
樵夫的大马甲
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行273.4375毫秒 RSS