查看: 4963|回复: 0

Catia二次开发源码分享: 通过鼠标点击创建直线

[复制链接]

4

主题

3

回帖

36

积分

管理员

积分
36
发表于 2017-4-17 21:56:09 | 显示全部楼层 |阅读模式

请使用QQ关联注册PLM之家,学习更多关于内容,更多精彩原创视频供你学习!

您需要 登录 才可以下载或查看,没有账号?注册

×

7 n# A9 B0 R$ }( ZCatia二次开发源码分享: 通过鼠标点击创建直线
+ B2 l( h1 B6 s$ c* W8 ?4 E7 }2 L8 s5 ]) a9 ?& M; y
" x8 Q  P2 d, x' w* r
) @9 p! G6 L# T& ^
#include "CAARCCreateLine.h"
0 c6 k9 {( _; [0 l#include "CATIndicationAgent.h"
3 I; ?+ \5 L  W( l# u#include "CATMathPlane.h"
# x7 B* S( W/ c, E( @! V9 d$ o8 D0 a# E$ j
#include "CATCreateExternalObject.h"  F" I/ }$ |7 a8 x' z( q8 r
, P. l; _6 C9 R: s1 D8 N5 E
#include "CATMathPoint2D.h"
+ O$ b! J  p) g3 q#include "CATMathPoint.h"
1 V4 p' [* {8 b8 [#include "CATMathPlane.h"
( P" @3 T  o9 _2 x* x9 F4 k
, r" R8 f& D1 w1 u#include "CATIGSMPoint.h": k- z5 e1 o; I0 F/ f
#include "CATIGSMLinePtPt.h": i6 K9 l2 \0 {5 p: a4 Q  w

+ k, a- E. N1 A8 s#include "CATFrmEditor.h"3 r0 s( N. ~) z8 O. ]
#include "CATPathElement.h"
* |+ v2 g. \2 r( Z1 o9 C9 G3 m) V3 B' ?/ f
3 H, Y% U' {2 l) m0 ^#include "CATIProduct.h"
8 F* {% t$ _- n, V- l# _#include "CATILinkableObject.h"/ U* T& ~$ p( f, a: u
#include "CATDocument.h"
# C# _' b2 l& \( k. O( U5 s7 v, E" C5 x" P- e
#include "CATIContainerOfDocument.h"
5 e2 H. z/ g& o. Y7 o+ k% H4 h7 J$ P8 T; _8 Q6 |6 m! H
#include "CATIGSMProceduralView.h", q. h2 }) {% B  y, m# D$ S7 M

( c% {0 s0 z8 I/ J8 S4 n#include "CATIContainer.h"
2 F3 A" Y% Q; p2 J5 K5 r* n#include "CATIGSMFactory.h"
; W. s- h. a! u! y1 a+ _. l) t$ i# J# Y! @+ y) ~
#include "CATISpecObject.h"
5 k0 D' o8 R$ N0 qCATCreateClass( CAARCCreateLine);0 `/ i4 \/ [# `: w3 m' U" Y1 a

% P# ~- k7 ]7 c; k- d) x$ R+ ?3 P) L4 G) S$ [4 s# q
//-------------------------------------------------------------------------
8 v7 T1 a  W: G. Y// Constructor
6 ^. j; m8 Y" T' W5 O3 Z//-------------------------------------------------------------------------" ^; o* S1 e, g+ u0 w, D9 o  U4 R
CAARCCreateLine::CAARCCreateLine() :
0 G; Z* c3 l7 T2 L& {  CATStateCommand ("CAARCCreateLine", CATDlgEngOneShot, CATCommandModeExclusive) ) m3 E2 I" Y: l& L3 h: S5 O0 K! A! K
//  Valid states are CATDlgEngOneShot and CATDlgEngRepeat
; J' [' F, r7 A. m5 Q( p3 ~: Z, _  ,_IndicationOnePoint(NULL),_IndicationTwoPoint(NULL)) n: `0 T- E7 d+ ^0 P$ s+ C- ~
{
+ J7 u7 m. h1 b+ [; |7 _# u, n}- [. `! F1 q8 g: R" w6 k3 S) C
- ^! V& c* ]4 |5 E1 q2 i
//-------------------------------------------------------------------------
1 a" x# W( t5 }% v# z// Destructor6 F; k  L1 T0 H$ ^7 y5 R
//-------------------------------------------------------------------------
# _, F  x& x0 g, j( q7 z) q  pCAARCCreateLine::~CAARCCreateLine()
! R& a- j2 {; r, S2 F{
- w8 C& `! v$ `* z- J   if (_IndicationOnePoint != NULL) - c3 o4 D. ^' G6 E- z: e; N1 g
      _IndicationOnePoint->RequestDelayedDestruction();
% u  x; q( S3 o! j+ p4 Q   if (_IndicationTwoPoint != NULL)
( h9 _' s, _) h: n     _IndicationTwoPoint->RequestDelayedDestruction();
" r/ u9 t) Z* x; k* Z( V* ]}
. g% l( s0 Q7 c" k+ W5 e; d/ N9 V9 H# B( P, J# `" E

1 D$ ~7 m5 [( P8 ]6 L//-------------------------------------------------------------------------7 \$ ?8 I! f0 |/ u- _
// BuildGraph()2 d* m( V2 L, a9 k4 O* V! e4 L
//-------------------------------------------------------------------------% }( ?# N' t+ q
void CAARCCreateLine::BuildGraph()  U) e) @& M7 q' R8 J% f! j
{, f% \) U% ?# U' p

! ?  \4 |' ^" |0 J2 f$ P9 @4 B( ]7 a5 W
  // TODO: Define the StateChart 3 s2 k2 W  s0 W- r; m& e' a, x1 z
  // ---------------------------$ d9 m# L! g( b5 a, G8 D- L
  _IndicationOnePoint = new CATIndicationAgent ("IndicationOnePoint");( h, s2 g6 T; ~2 \2 @! o+ E
  AddCSOClient(_IndicationOnePoint);
3 Q, I# G) L& `, z+ g& N; e3 i! H, s8 f) d
0 y7 |! l5 @; M  _IndicationTwoPoint = new CATIndicationAgent ("IndicationTwoPoint");* M9 p2 }, e5 Z8 T( [  ?1 }9 {% `

6 l1 g, M; d, h, t2 G9 w  CATMathPlane PlaneXY;
5 ?, _8 t& I# C8 k  _IndicationOnePoint -> SetMathPlane (PlaneXY);
+ l, v% w& T" j  z) R5 B  _IndicationTwoPoint -> SetMathPlane (PlaneXY);7 a4 K2 [! i2 A% T- L: [) R; P8 g/ e

8 F: t. J1 h. R$ a  CATDialogState * initialStateOne = GetInitialState("选择第一个点位置");
( O8 G( T8 W- ?  initialStateOne -> AddDialogAgent (_IndicationOnePoint);
, v3 D# Z. ?) T8 z) Z- {
8 k3 R. Z/ E: {: W% ?: T  CATDialogState * initialStateTwo = AddDialogState("选择第二个点位置");
; C/ ~0 k' @9 y4 b( @. H  initialStateTwo -> AddDialogAgent (_IndicationTwoPoint);3 T4 \! Z9 P5 m, l. K3 N! L, \3 e& Z
5 }3 |" M4 X4 O) @* ]+ d
  AddTransition( initialStateOne,
# u: N8 j. V0 U8 ?" B( F                 initialStateTwo,
# O/ D, X2 q. ^2 F" F; i. u                 IsOutputSetCondition (_IndicationOnePoint)," ]# F& [# @) L% K
                 Action ((ActionMethod) &CAARCCreateLine::ActionOne));
$ z4 {! H; \/ q) ]3 v# f: C7 ~% }. R
  AddTransition( initialStateTwo, . }. c$ ~  _; d+ S5 m3 ?
                NULL,
1 S- i* J7 _* m( z/ M                IsOutputSetCondition (_IndicationTwoPoint),* L- W! H8 w) C( Y# H
                Action ((ActionMethod) &CAARCCreateLine::ActionTwo));$ H1 M6 g" d# r+ V
}
8 f7 e8 o# x2 ?- |/ _0 ^$ Z1 L& O! ^+ e
" i& E; h0 K3 ?0 U4 \; l
//-------------------------------------------------------------------------( w" Y$ Y8 U/ {) j2 Q3 V" w" `. N
// ActionOne (): o; u3 p) }: w# b
//-------------------------------------------------------------------------
% m0 C* W( i# F3 oCATBoolean CAARCCreateLine::ActionOne( void *data )
0 W: g7 `+ W( H+ C% Y2 |{% y% v. g4 \3 D9 o: p* |8 N2 v# |! S
  // TODO: Define the action associated with the transition . e2 F; {% v& I6 b, m0 u; T
  // ------------------------------------------------------- i; j. M% H5 `% Q) H9 g
  CATMathPoint2D point2D = _IndicationOnePoint->GetValue();//获得一个2D的点  A) q/ w( h1 Q0 I. Y
" h2 R$ o* I. z' R& v# l
  CATMathPoint Point3D;' n7 U$ m4 E6 @4 `9 r2 |& b$ T
  CATMathPlane Plane = _IndicationOnePoint->GetMathPlane();
# S0 t1 d3 W- a% q7 G4 R' G
  ]* z$ ^' t8 f. ~; H( W  Plane.EvalPoint(point2D.GetX(),point2D.GetY(),Point3D);                //将2D点转换为3D点
4 L  U* z: u3 Q9 P
4 J1 _5 k' {# u0 I' z$ @  //设置Container(非根节点)
9 q' Z) L' X) L. t8 t- _  //获得Editor
! ]0 _0 ]  @# j, o; Z) @  CATFrmEditor* pEditor = CATFrmEditor::GetCurrentEditor();& p$ K& N! X. `2 s. u: N; m
. D. W9 T$ N% _
  //得到当前对象的文档4 L. k' \' J% O( F# |
  CATDocument * pDocument = NULL ;) ]. m7 j4 F0 X9 U& ]$ L! `

( u4 a2 g' g. V( V9 F1 u+ e  //取得当前活动对象
; P) C- M6 P8 B- B: \" C# H- }  CATPathElement activePath = pEditor->GetUIActiveObject();
! Q3 N; {9 p- n# D1 d) v" X: p5 v
6 J: a" G$ c. h# Y6 U& |  //取得当前活动的product
; U  b9 _# F1 F. y  CATIProduct *pActiveProduct = (CATIProduct *)activePath.SearchObject(CATIProduct::ClassName());( J. @" ^; k# n* G9 T
8 o2 m( A! O3 a3 b. k, f; w
  //当前活动对象不存在
) C; Y: ]; G- J/ c  if (pActiveProduct == NULL)' [6 j6 U3 G9 v" ?1 B2 t
  {
5 A) }4 ]0 B7 y2 s    pDocument = pEditor->GetDocument();6 v/ u# X' q2 X$ _8 m; J9 e
  }* \' T6 M3 B7 K) D1 F
  else9 J' z& {9 |8 w0 ]. g) V( \
  {+ v; I2 h5 r5 k
    CATIProduct_var spRef = pActiveProduct->GetReferenceProduct();5 }9 s4 m! J7 g
    //当前对象的引用对象是否存在: z4 _2 }( E' S6 ?& L
    if ( NULL_var == spRef )
& x3 V- l  `; i' h* {    {
2 z1 T7 ~8 u& g  F' `# `      return FALSE;' l8 ]7 F8 F, F! X
    }
2 r5 l2 n2 `6 d4 S, x* k, X+ W% d6 r/ c/ R; `
    //当前对象的链接对象
5 ]$ u4 u& a5 ?' b    CATILinkableObject * piLinkableObject = NULL;
2 U, T1 l" }) `3 o    HRESULT rc = spRef->QueryInterface( IID_CATILinkableObject, (void**)& piLinkableObject );                            5 i; @& |* U, |2 P3 z
    if ( FAILED(rc) )
) Q! j, m! p$ S    {
' d% T2 q3 r" ~7 Y7 ]* a* R1 c% H      piLinkableObject->Release();
" A" I1 g) y) x! f      piLinkableObject = NULL ;
* D; @( x7 g5 R, A& m  l- M0 |      return FALSE;, j. b5 t* O+ N( r
    }$ k, {5 M/ a5 r9 P# u5 b

" H' c" s; S. A& K    //得到当前对象的文档: k  p* [  e! Z1 X/ [! P
    pDocument = piLinkableObject->GetDocument();
7 g! G2 G1 N2 r) ~/ ?    piLinkableObject->Release();
% u! z/ W2 T; n    piLinkableObject = NULL ;
2 r1 p7 i5 }% W1 d, |- i. R, @* N) W8 Q: Y5 ?
    if ( NULL == pDocument)
5 D, V2 Y4 k: J" X+ {    {) f( X; c' C; Q" g2 t8 v9 d- r
      return FALSE;
0 J1 j8 m1 T5 Z* p2 i# Y    }
# X4 _! l' i' u0 W- u4 h2 D  }0 X6 Z" ^' T3 W6 T- x
/ j. ?* z. F8 S( `) t& A' K4 y
  //得到文档容器集5 U8 V8 x6 W) t8 d' f, K$ I
  CATIContainerOfDocument * pIContainerOfDocument = NULL;1 }5 c; Z, `+ q, `* n: k
  HRESULT rc = pDocument->QueryInterface(IID_CATIContainerOfDocument, (void**)&pIContainerOfDocument);
( q1 t% X$ v# N' j% N  if (FAILED(rc)), M. m0 l: M5 u' S6 G" H  Y
  {* H; t  x4 b; {, A1 r( R( N
    //pIContainerOfDocument->Release();+ X' K5 O( @9 J1 `; z
    pIContainerOfDocument = NULL ;
1 `# r: D: u/ V! p    return FALSE;& x3 Y( w" P3 V* t* [
  }
  U2 O5 Q! u: w" Y- M# y" d( n6 w! X$ e$ f
  //获得Document' `7 x! r& W6 C: E
  CATIContainer* _pContainer = NULL;        / N- Q) z  r3 |: k
  //获得SpecContainer% }& l5 V7 J6 l3 N% R- N* u
  HRESULT hr = pIContainerOfDocument->GetSpecContainer(_pContainer);7 K3 i& u5 l* g) }: S
        # w) C$ `0 X1 y4 _1 n. {* T
  //GSM工厂
3 o* g+ o* W" @7 {  CATIGSMFactory_var spGSMFactory = NULL_var;
# [9 V' Y& @5 `2 }' `$ `3 u( K  //设置工厂               
0 v6 E# |8 t: U: R  spGSMFactory = _pContainer;                                                                       
( K1 b* b; M, R3 r9 c5 H! P" x# S: a: m, y
  CATIGSMPoint_var spPoint = spGSMFactory->CreatePoint(Point3D);" Q$ M* R% C- k# \6 Y9 b
: N! I2 t" q* C" e2 f  ^
  spSpecPoint1= spPoint;                                       
2 \' _& C4 e' w) d3 Z3 [) f# ~6 a& x5 m5 @- S
  CATIGSMProceduralView_var spSndPntObj = spSpecPoint1;, `7 k2 U. I1 s- `9 h7 y
" _9 i0 H& z4 E: B8 d
  //*将点显示在屏幕上
& B: ~: u# E/ R9 ]" z, w  spSndPntObj->InsertInProceduralView();
+ l& \; X0 U8 E' z
* j$ ^1 B4 S7 B, e" T0 h+ \4 }2 h  spSpecPoint1->Update();
& @! D( a; P0 D% Z' t6 t
* h' n" ~8 S, B8 J  return TRUE;% c. g& B3 X- k7 ~: ?+ X7 `' t
}
$ Q6 t. {6 a7 w" `1 n/ {$ p+ _" V; ]: o& n
//-------------------------------------------------------------------------. S' b' r0 ~' m/ \6 O  a' w( V
// ActionTwo ()
& u7 e% H% q: K" j//-------------------------------------------------------------------------0 Z) Y" ~8 C5 A- ~- i$ w
CATBoolean CAARCCreateLine::ActionTwo( void *data ), C4 h' ~6 S6 f% ^, v2 {# x
{
9 b' b8 }1 v' d( q" H  // TODO: Define the action associated with the transition
) D5 ^; x; N# z$ f7 `4 L  i; o  // ------------------------------------------------------
6 o! @7 D* n* B! {* C6 ]# \) `  CATMathPoint2D point2D = _IndicationTwoPoint->GetValue();//获得一个2D的点/ |8 y4 F& S! Y( a( q  P& o

0 w- y$ N' c+ `, v8 |  CATMathPoint Point3D;
( Z: Z6 p1 N+ ?: Q  CATMathPlane Plane = _IndicationTwoPoint->GetMathPlane();
4 y5 u1 m2 ^& e5 p' Y8 V) ?) L9 v3 K4 ^1 z
  Plane.EvalPoint(point2D.GetX(),point2D.GetY(),Point3D);                //将2D点转换为3D点' n' S; q  u% _7 H* C* Z% c' ~* t6 B
, o3 N1 O/ O4 ~2 H4 K0 U
  //设置Container(非根节点)- C7 O! ~( a; u# S7 `% W
  //获得Editor
' b  I) |( B  t) _- F: N% }! U  CATFrmEditor* pEditor = CATFrmEditor::GetCurrentEditor();. x! }( j/ ]8 V: [  u
7 G# _- z* w. w
  //得到当前对象的文档
3 i* I4 O% d! R3 A6 ?- N  CATDocument * pDocument = NULL ;
6 U6 q- O9 z2 b" ?* d1 t3 q+ }' e5 ?8 Z9 \$ O
  //取得当前活动对象
" [1 `; Z8 e/ v' h+ y1 X. l) t. q  CATPathElement activePath = pEditor->GetUIActiveObject();/ i9 M  T0 C2 [- ?' [1 S! s) H
: z  b6 p9 J, n
  //取得当前活动的product
1 r) S. r9 }9 T2 B5 `/ M  CATIProduct *pActiveProduct = (CATIProduct *)activePath.SearchObject(CATIProduct::ClassName());
# P. [; \5 \' P& S1 V4 Z% ]! }7 w! J, M! t( |
  //当前活动对象不存在0 M5 G' }  U; P0 L/ r) ?! x
  if (pActiveProduct == NULL)6 S8 k' O) C3 j) l: K+ R
  {" E3 j2 v3 Y1 w- |0 R. t3 l
    pDocument = pEditor->GetDocument();
1 ^, X! B2 F& I  }
( t/ M% B: P, \# R5 \: _! K( r, `/ L8 g  else
7 x4 B/ G. v! l! s  {6 o* g0 W& G3 P/ F2 O6 Z/ X
    CATIProduct_var spRef = pActiveProduct->GetReferenceProduct();
; w9 ^; _7 S8 ]: \8 I2 b5 g6 H    //当前对象的引用对象是否存在
0 e( g8 a! t. a    if ( NULL_var == spRef )
. d/ B' G: s, f' [. D8 C  W    {
4 a- \9 e' n! L3 P1 k# c9 p      return FALSE;. ^% \. ?5 U$ V6 J$ b
    }! A3 n- Z6 f* G) w$ Q3 l; K6 Q5 G% }2 {7 X

9 G$ m; Q5 N0 e  ^    //当前对象的链接对象* ^( w* p) a6 x9 _$ r/ _* Z  _
    CATILinkableObject * piLinkableObject = NULL;/ D% u' a# G: n/ a, d8 T% C7 k9 n; P
    HRESULT rc = spRef->QueryInterface( IID_CATILinkableObject, (void**)& piLinkableObject );                            - Z7 ^! `/ g" ~3 M: L! |  g
    if ( FAILED(rc) ): P9 Q  b1 R5 _7 o( M- l
    {
# s0 h  l( ]" Q2 ^9 k      piLinkableObject->Release();7 o( v  e  F2 L# o9 x8 ?0 ^
      piLinkableObject = NULL ;, M$ D& f) {" q, [
      return FALSE;3 g' d% w4 g8 }5 w+ \* Z6 ?
    }. E/ T2 T  Z! @$ }; n( F
7 I8 {0 x- j5 t& ?( t
    //得到当前对象的文档+ }1 Y( Y6 K0 D1 C. z  Z6 C8 v' J
    pDocument = piLinkableObject->GetDocument();
# [: [6 j. y% H' ?  I9 q    piLinkableObject->Release();$ _9 i: d4 c! [8 @' Q& o" h. E
    piLinkableObject = NULL ;
* ^. Z0 @  D2 F$ m& v0 p
2 y* }* z& `0 [$ V    if ( NULL == pDocument)
+ {8 v/ O) Q: m0 W$ u    {* W2 k0 E+ T0 R
      return FALSE;$ V4 w) M, j# h6 R4 h5 P6 [/ [$ W
    }& M+ A  J  I$ U# i6 C
  }8 v" i, m1 @6 x: E! h0 V& ]( }

" k$ J' Q9 k# |7 |$ k. O$ h  //得到文档容器集, h& N7 y4 ]/ A- c  h
  CATIContainerOfDocument * pIContainerOfDocument = NULL;) J: p2 [& M) |/ R
  HRESULT rc = pDocument->QueryInterface(IID_CATIContainerOfDocument, (void**)&pIContainerOfDocument);
* t/ e; s1 p' j$ m- ]) n. Y% ~  if (FAILED(rc))3 C& K6 ^3 F" |7 m8 e
  {
% m- ]! o# L) ^, n0 \    //pIContainerOfDocument->Release();
# ?9 n4 r, j' S0 x    pIContainerOfDocument = NULL ;
6 G  C1 H& k( ^# Q- z3 |% I    return FALSE;
1 c) [* `) j( F) v  }
' C- ~4 }: v9 E/ W" s" c, ?# q, \, E) O& e
  //获得Document
, f! b% m, C( k  CATIContainer* _pContainer = NULL;          j* N2 I4 b5 O
  //获得SpecContainer
$ f* L' n: c' p( K$ {+ K# H  HRESULT hr = pIContainerOfDocument->GetSpecContainer(_pContainer);
/ ^- k/ J5 R! n* P& f7 Q        4 H) A7 _! A( J% _, w
  //GSM工厂
* P( {9 J2 K; M. P7 [% j  CATIGSMFactory_var spGSMFactory = NULL_var;. j- D6 M! D2 Y0 R2 o
  //设置工厂               
- x; b" ~" F; X* o  spGSMFactory = _pContainer;                                                                       
- m, a3 b) t# N8 u4 J# x5 @1 g6 Y9 L
  CATIGSMPoint_var spPoint = spGSMFactory->CreatePoint(Point3D);( A+ w3 B; \/ S2 a' U

& L& b9 k3 b4 Z4 c, r1 L) A: M  CATISpecObject_var spSpecPoint2= spPoint;                                       
% a  b9 d9 x0 J" s: G2 p
1 V" u) O: ]/ x" g  CATIGSMProceduralView_var spSndPntObj = spSpecPoint2;5 A7 P9 L7 P. i, l- C! C4 m
' U5 _4 O$ z1 R6 s$ j
  //*将点显示在屏幕上3 T% r7 {6 b# x: Q3 W
  spSndPntObj->InsertInProceduralView();0 L. p7 O' o- o: E; V, n. v
( T$ D  r* s( Q6 q1 N3 y, T6 U
  spSpecPoint2->Update();
' g- J' ^. q$ f5 [; a8 y$ f  z' R( ~, q
  //生成线
9 J" O3 V' }0 s" ~& F$ N6 i0 t/ S& w  CATIGSMLinePtPt_var spLine = spGSMFactory->CreateLine(spSpecPoint1, spSpecPoint2, NULL_var);
2 R4 [' b9 c6 J; Q; \9 m9 }* |" J& O9 ?# F4 |
  CATISpecObject_var spSpecLine= spLine;                                       
% H1 S* _' |6 \6 N7 Q
8 `6 y1 f, e. K! v  CATIGSMProceduralView_var spSndPntObjLine = spSpecLine;2 W/ r, b# e; z5 g7 ~0 F

( k, o$ B" b2 h  ?  //*将线显示在屏幕上8 P3 V3 ~- l  N2 q; W
  spSndPntObjLine->InsertInProceduralView();
1 L) ?8 `$ q5 o2 u+ q
# t' G+ i. T% m8 T) U  spSpecLine->Update();
! ?, f: {6 l4 W  E) l! m1 Q4 w8 Y) i6 x
  return TRUE;
9 m. S, d- x! Y) j+ \+ p# Q, k* d}
+ }* h. c, J1 c) c" V0 w( F! A# p
7 r6 a) L  u  x4 e6 v, s
7 H* R, u+ U1 E, }
上海点团信息科技有限公司,承接UG NX,CATIA,CREO,Solidworks 等CAx软件,Teamcenter,3D Experience等PLM软件,工业4.0数字化软件的实施\二次开发\培训相关业务,详情QQ 939801026 Tel 18301858168 网址 www.doteam.tech
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

在本版发帖
关注公众号
QQ客服返回顶部