aardio 官方社区

 找回密码
 注册会员

QQ登录

只需一步,快速开始

搜索
查看: 181453|回复: 129

实例教程:多账号批量登录网页操作程序

 火... [复制链接]

52

主题

1270

回帖

7276

积分

荣誉会员

积分
7276
发表于 2011-7-17 00:35:12 | 显示全部楼层 |阅读模式
由于115网站改版了,该代码已不能直接运行,仅提供思路学习,有兴趣自己可以看着网页源码自行修改

该示例程序以“115网站”为例,列举多账号登录网站并实现“摇一摇”获取空间功能,透过此例,大家可掌握父子窗体操作、网页操作、用户库定义等方面知识。

  • 前缀
    1. 认识aardioIDE

    aardioIDE分为2个界面:主页界面、语法界面(在WINDOWS窗体设计器可用TAB选项卡控件实现类似功能)

2011-07-14 14 05 55.jpg

语法界面比较适合对语法语句还不熟悉的新手写代码使用(我就比较喜欢使用语法界面写代码)

2011-07-14 14 06 51.jpg


更多的开发技巧可点击浏览此贴,同时也希望你能分享自己的开发技巧心得。

   2. 语法知识

      aardio的帮助手册有很详尽的语法知识,里面详细点缀了aardio语言的特点,无论你是否有编程基础,此部分内容一定要阅读并熟练掌握,如果你没有编程基础,里面有些专业词语不明白时,可善用搜索引擎,学习态度决定一切,成功者从来都属于主动并行动的人。

2011-07-14 14 27 47.jpg


  3.范例

  软件自带有许多范例,里面的范例都涉及到标准库应用及常用功能应用等知识要点
  如果你把所有范例都掌握,那么你肯定属于中高级程度了。

2011-07-16 20 30 42.png


4.aardio论坛也是学习最佳的途径之一

新手教学版,无论是文档分类还是提问分类,都有很基础的知识讨论及解答,如果你对基础知识有疑问的,也可以在这里寻求答案。

另外标准库的各个分类也有许多知识涉及,请善用搜索功能,寻找需要知识学习,同时也欢迎你分享学习心得,大家一起进步!


点评

真棒: 5.0
真棒: 5
这么好的帖子,必须支持  发表于 2012-1-14 20:35

评分

参与人数 4 +151 收起 理由
满月星光 + 40 赞一个!
relaxlee + 1 很详细,正需要,尽快学习~
ihelpsoft + 20 感谢写得这么仔细
fantasynew + 90 赞一个!

查看全部评分

52

主题

1270

回帖

7276

积分

荣誉会员

积分
7276
 楼主| 发表于 2011-7-17 00:35:14 | 显示全部楼层
本帖最后由 qqmmcc 于 2011-8-2 12:22 编辑


一。用户库(库是aardio的特色,也是最优势的地方)

1.1 知识要点

       库就是模块,用于支持模块化编程, 模块化编程,能使代码结构更合理、思路更清晰。      
       库就是为更好的复用代码而设计的。 别人写好的库,也可以直接拿来用。

      使用import导入库有许多优点,不会重复导入相同的库,保证需要用到的函数只会加载一次,效率最好
      也不会覆盖现有的函数,因为在不同的名字空间中,避免了名字污染

       用户库就是一个普通aau代码文件,只不过放在所在工程的lib目录下;
       标准库、用户库是完全一样的,只不过放的位置不同


   用法见下图:在用户库目录点击添加新建用户库
(倘若已有用户库,可复制到所在工程目录的lib目录里,打开工程即显示,或浏览目录添加)

2011-07-15 12 56 31.jpg

2011-07-15 13 14 29.jpg


输入文件名打开即进入用户库的编辑代码界面

2011-07-15 13 17 55.jpg

在新建库的 namespace myfun{  } 内部写公用的函数 其他任何需要调用的地方一句 import myfun 就搞定

用户库也支持智能提示

2011-07-17 16 38 11.png



2.1程序实例

在本示例工程,我创建了一个my.aardio的用户库。里面封装了几个常用函数,
只为演示所用,所以没有按功能类别设置用户库(这不是好习惯),
实际操作,用户库可按函数功能进行不同的封装,分类比较好。

my.aau用户库代码如下:
import win;
import inet;
import inet.ras;   
import process;

namespace my

//定义随机时间函数
randomTime = function(mintime,maxtime){
   
/*var语句声明的变量作用域限于函数内部*/
    ..math.randomize()
   
var temp = ..math.random(mintime,maxtime);
   
var result = ..win.delay(temp)
   
return result;
}

     

//定义拨号函数
dialLink = function(){
    ..inet.clearCookie()   
   
var tab =..inet.ras.getEntries()
   
var ljm = tab[1].entryName
    ..process.
execute("rasphone.exe","-h "+ ljm); //挂断
    ..win.delay(3000)//一定要.. 否则会出错
    ..process.execute("rasphone.exe","-d "+ ljm); //拔号
               
}



/*封装最小化到托盘并弹出信息函数*/

import win.ui;
import win.ui.menu;

traypopMenu=
function(winform){//创建弹出菜单   
    winform.traymenu = win.ui.popmenu(winform);
    winform.traymenu.add(
'打开窗口',function(id){
   
//在下面输入菜单响应代码
        winform.show(true)
        tray.delete()
    })
    winform.traymenu.add();
//分隔线
    winform.traymenu.add('退出',function(id){
        winform.close() }
    )
   
}


trayPop =
function(winform,info){//托盘信息
    winform.wndproc = function(hwnd,message,wparam,lparam){
        
select(message) {//判断消息类型
                case( 0x400/*_WM_USER*/+9981 ) { //托盘图标消息
                    select(lparam){
                        
case = (0x203/*_WM_LBUTTONDBLCLK*/ ){//双击托盘图标打开窗口并删除托盘
                           winform.show(true)
                           tray.delete()
                        }
                        
case = (0x205/*_WM_RBUTTONUP*/ ){//单击鼠标右键弹出菜单
                            import mouse;
                            x,y = mouse.getPos();
                            winform.traymenu.popup( x,y,
true )
                        }        
                     }                                                                                         
                }
               
case( 0x112/*_WM_SYSCOMMAND*/ ){ //系统命令消息
                        if( wparam == 0xF020/*_SC_MINIMIZE*/ ){ //用户点击了最小化按钮                              
                                import win.util.tray;
                                tray = win.util.tray(winform.hwnd)
//创建托盘图标
                                tray.message = 0x400/*_WM_USER*/ + 9981 //设置托盘图标回调消息
                                tray.pop(info)
                                winform.show(
false); //隐藏窗口
                                return true;//阻击默认消息传递,取消最小化过程
                        }
               }
        }           
    }
}

/**intellisense()
randomTime(min,max) = 随机延迟时间\n可选参数(最小,最大)
dialLink() = 清cookie拨号
traypopMenu(winform) = 托盘弹右键点击出菜单
trayPop(winform,info) = 设置最小化托盘图标\n参数(winform,图标消息)
end intellisense**/





52

主题

1270

回帖

7276

积分

荣誉会员

积分
7276
 楼主| 发表于 2011-7-17 00:35:15 | 显示全部楼层
本帖最后由 qqmmcc 于 2011-8-2 12:22 编辑



二。窗体主程序main.aardio

2.1知识要点

新建对话框工程后,系统则进入该页面,在工具箱-界面控件选择所需的控件直接拖到窗体即可
                           功能组件,非可视控件,点击所选组件,即进入代码编辑界面,自动生成代码

2011-07-15 14 50 15.jpg                   2011-07-15 14 50 23.jpg

若想了解相关的windows窗体使用控件的属性、事件、消息等用法,详尽的资料可参阅微软的MSDN档案

aardio的库源码及软件携带的windows消息大全也有部分内容

2011-07-15 16 13 17.jpg

在论坛的win程序设计(win) 版面也有许多相关讨论,遇到问题请善用论坛搜索,如搜索不到可提出问题。



2.2实例程序

在此实例中,功能简单设计:
   导入账号资料---->点击开始----->打开WEB窗体(隐藏不显示)---->循环自动登录并摇一摇---->结束运行
2011-07-17 14 53 48.png

[一键续期] 功能暂未实现,有兴趣的朋友可以自己实现,作为练习

作为账号资料的简单保存配置文件,可选择ini、txt、lst后缀文件,在此示例我选择了lst文件(string.list库支持)关于lst文件及用法可参考软件自带范例:文件操作---字符串列表

在主程序创建子窗口,在资源文件夹(res)添加文件即可。
2011-07-15 21 33 20.jpg

然后直接拖动aardio文件至主窗口代码区,即自动生成以下代码:
var child,wb = winform.loadForm("\res\115web.aardio", );
child.show();

使用winform.loadForm 导入子窗体aardio文件,父子窗体之间调用函数非常方便,无论在子窗口或主窗口定义的全局函数,在各自窗体调用对方文件定义的函数时直接写:函数名() 即可

按照思路设计控件窗口,并就近原则封装定义函数,详见代码:
import win.ui
import fsys.dlg;
import process;
import my;//导入用户库

/*DSG{{*/
var winform = win.form( right=349;bgcolor=15780518;bottom=450;max=false;text="115工具   by qqmmcc" )
winform.add(
importing={ bottom=258;right=103;left=33;top=229;font=LOGFONT( name=
"宋体";h=-12 );z=8;text="导入";cls="button" };
static={ bottom=444;color=0;right=290;left=70;top=426;font=LOGFONT( underline=1;h=-12;name=
"宋体"; );z=11;transparent=1;notify=1;text="点击获取该软件教程及源码";cls="static" };
chooseip={ bottom=69;right=104;left=32;
items={
"1";"3";"5" };font=LOGFONT( name="宋体";h=-12 );text="3";z=6;top=49;mode="dropdownlist";edge=1;cls="combobox" };
ip={ bottom=69;right=297;left=137;top=51;font=LOGFONT( name=
"宋体";h=-12 );transparent=1;z=9;text="<---选择运行N个账户后换IP";cls="static" };
renewal={ bottom=37;right=299;left=228;top=22;font=LOGFONT( name=
"宋体";h=-12 );z=4;text="一键续期";cls="checkbox" };
login={ checked=1;bottom=38;right=92;left=29;top=22;font=LOGFONT( name=
"宋体";h=-12 );z=2;text="登录";cls="radiobutton" };
exit={ bottom=185;right=102;left=32;top=156;font=LOGFONT( name=
"宋体";h=-12 );z=7;text="退出";cls="button" };
status={ bgcolor=16777215;bottom=261;text=
"listbox";left=134;right=308;top=80;font=LOGFONT( name="宋体";h=-12 );z=5;vscroll=1;
items={  };edge=1;cls=
"listbox" };
yao={ checked=1;bottom=37;right=192;left=128;top=22;font=LOGFONT( name=
"宋体";h=-12 );z=3;text="摇一摇";cls="checkbox" };
start={ bottom=117;right=101;left=31;top=88;font=LOGFONT( name=
"宋体";h=-12 );z=1;text="开始";cls="button" };
account={ bgcolor=16777215;vscroll=1;bottom=418;text=
"listview";left=34;fullRow=1;top=282;font=LOGFONT( name="宋体";h=-12 );z=10;gridLines=1;right=309;edge=1;cls="listview" }
)
/*}}*/

//初始设置

winform.chooseip.selIndex=2
//设置默认运行3个账户后换IP

//设置账户列表
winform.account.insertColumn("账号",90,1)
winform.account.insertColumn(
"密码",90,2)
winform.account.insertColumn(
"获取空间",90,3)

//设置最小化窗口弹出托盘图标,使用用户库封装的函数
my.traypopMenu(winform)
my.trayPop(winform,
"115网盘工具")


/*
设置手动登录操作弹出菜单
*/


winform.lvpopmenu = win.ui.popmenu(winform);
//创建弹出菜单
winform.lvpopmenu.add('手动登录操作',function(id){

   
//在下面输入菜单响应代码
    child,wb = winform.loadcode("\res\115web.aardio",winform /*指定父窗口*/ )
    child.show()
//由于WEB窗体默认不显示,这里需要显示手动操作
   
    user=winform.account.getItemText(winform.account.selIndex,1)
    pass=winform.account.getItemText(winform.account.selIndex,2)
    login(user,pass)
   
});

import mouse;
winform.account.onnotify =
function(id,code,ptr){
   
if(code==0xFFFFFFFB/*_NM_RCLICK*/){
        
var x,y = mouse.getPos()
        winform.lvpopmenu.popup(x,y,
true);//弹出菜单
    }
  
}


//点击"开始",再点击"停止"
winform.start.oncommand = function(id,event){
   
if(!tlist){win.msgbox("请导入资料","aardio");return ; }
   
if( winform.start.text == "开始" ){ //开始循环      
        winform.start.text = "停止"
        child,wb = winform.
loadcode("\res\115web.aardio",winform /*指定父窗口*/ );
        win.delay(100)
        execuLoop()
//执行循环操作
        return ;
     }
   
if(winform.start.text=="停止"){ //结束循环
        winform.start.text = "开始"
        
return ;        
    }      
}


//退出程序
winform.exit.oncommand = function(id,event){
    winform.close();
    win.quitMessage();
}


//导入账号密码
import string.list;

winform.importing.oncommand =
function(id,event){   
    dir=fsys.dlg.open();
//打开文件夹选择文件
    tlist = string.list(dir)
   
for i,na,ps in tlist.each() {
        winform.account.addItem()
        winform.account.setItemText(na,i,1)
        winform.account.setItemText(ps,i,2)
    }   
}


//定义选择运行N个账户换ip
chooseIp = function(n,m){
   
   
if(n>=m&&n%m=0){
            msg(
"正在断线拨号请稍候")
            my.dialLink()
            my.randomTime(10000,15000)         
            msg(
"-------------------------")
    }               
}


//判断选择项,若勾选了摇一摇则执行摇一摇
selChecked = function(row,user){   
   
if(winform.yao.checked=1){
        msg(
"准备摇盘...")      
        
var text = yao()//yao()函数在web窗体定义,在主窗体执行
        winform.account.setItemText(text,row,3)
        msg(user+
"获取"+text+"空间")
        
return ;
    }
   
if(winform.yao.checked=0){      
        
return ;
    }
}


//定义循环执行事件
execuLoop=function(){   
   
var num = tonumber(winform.chooseip.text);
   
for i,na,ps in tlist.each() {      
        
if(winform.start.text=="开始"){
            
break ;
        }      
        win.delay(1000)
        msg(na+
"正在登录,请稍候...")
        checkLogin(na,ps)
        msg(
"登录成功...")  
        my.randomTime(1990,4999)            
        selChecked(i,na)        
        my.randomTime(2990,5999)
        msg(na+
"正在退出...")      
        logout()
        msg(
"-------------------------")   
        my.randomTime(5000,10000)                  
        chooseIp(i,num)                             
    }
    msg(
"所有账户操作完毕")
    winform.start.text=
"开始";
   
return ;
   
}


/*显示消息*/
msg =
function(s){
        
//信息在列表框里显示        
        winform.status.add(s);
        winform.status.redraw();
        ::SendMessageInt(winform.status.hwnd,0x115
/*_WM_VSCROLL*/,0x3/*_SB_PAGEDOWN*/,0);   //自动滚动列表框到底部
   
}


winform.static.oncommand =
function(id,event){
   
    process.
execute("http://bbs.aardio.com/thread-2355-1-1.html")
   
}

import win.cur;

//鼠标回到窗体上时,切换鼠标为箭头
winform.wndproc = function(hwnd,message,wparam,lparam){
   
if(message =  0x20/*_WM_SETCURSOR*/){
        win.cur.load(0x7F00
/*_IDC_ARROW*/)
        win.cur.setCur();
    }
}

//当鼠标指针移到静态控件上是,切换鼠标为手形
var hand = win.cur.load(32649/*_IDC_HAND*/)
winform.static.wndproc =
function(hwnd,message,wparam,lparam){
   
if(message = 0x200/*_WM_MOUSEMOVE*/) {
        win.cur.setCur(hand);
    }
}

winform.show();
win.loopMessage();
return winform;


52

主题

1270

回帖

7276

积分

荣誉会员

积分
7276
 楼主| 发表于 2011-7-17 00:35:16 | 显示全部楼层
本帖最后由 qqmmcc 于 2011-8-2 12:23 编辑



三。WEB子窗体

3.1 知识要点

此例采用模拟手工操作方法,因此采用web窗体,为了演示父子窗口之间的函数传递,我采用了父子窗体模式,而要隐藏WEB窗体方法是许多的(留给大家去发挥)。。。

aardio操作WEB窗体有绝对优势,aardio直接支持JS 、JQ, 相互之间调用非常方便,详细可参阅帮助手册-web内容

225219xw6z536kz663qjqf.jpg

关于WEB窗体操作,在论坛也有许多视频及帖子有相关介绍。

1.aardio 网页操作专题(已更新2个视频)

2.取得指定网页节点的方法归纳

3.网页自动填表自动登录自动点击模拟代码汇总

4.自动登录方法汇总

5.DOM方法与属性

6.Javascript 事件列表

7.aardio执行网页JS脚本代码

在学习过程中遇到问题也可到 web程序设计(web) 版面提出问题



3.2 程序实例

在此例中,介绍使用aardio最强悍的网页操作工具--网页探针

113708d83mujkoeuzmoo6v.png

打开探针,登录网站,获取“摇一摇”的节点,很快很方便地找到,使用该工具胜过你慢慢查看源码查找框架代码。

113707pwnk2f50cjow7n1n.png

接下来,根据各功能封装定义WEB相关操作函数,然后在主窗体程序调用该函数。详见代码
import win.ui;
import my;//导入用户库

/*DSG{{*/
var winform = win.form( bottom=409;scroll=1;right=605;text="aardio Form" )
winform.add(  )
/*}}*/

import web.form;

//创建web窗体
var wb = web.form( winform
    ,
//可输入_UIFLAG_ 前缀的常量自定义外观
    ,//可输入_DLCTL_ 前缀的常量以控制下载行为
    ,//"USER AGENT"
    );

//打开目标网站
wb.go("http://u.115.com/")

wb.wait()


//定义登录函数
login = function(user,pass){
    win.delay(3000)
    wb.getEle(
"account").value = user
    wb.getEle(
"passwd").value = pass
   
var ele = wb.getEle("passwd")
    ele.form.submit()   
   
}

//定义退出网站函数
logout = function(){
    wb.go(
"http://passport.115.com/?ac=logout&goto=http%3A%2F%2Fu.115.com")
   
}

//定义点击链接函数
clickLink = function(title){
   
for(k,ele in wb.eachAll("A","main_frame") ){
        
if(string.find(ele.innerHTMl,title )){
          ele.click();
         
break;
        }
    }
}


//定义检测登录状态函数
checkLogin = function(user,pass) {         
   
if (wb.location=="http://u.115.com/") {
        login(user,pass)
        
    }
   
else{
        logout()
        login(user,pass)
        
    }
}

//定义摇一摇函数,返回获取空间
yao = function(){   
    win.delay(1000)
    ele = wb.waitEle(
"js_get_space_btn","main_frame",11000)//透过网页探针很快找到框架代码
    if( ele ){
        ele.click()
        win.delay(100)
        clickLink(
"开始摇奖")//点击链接     
        win.delay(6000)
        
for k,span in wb.eachAll("span","main_frame") {//查找获取空间
            if(string.find(span.innerHTMl,"恭喜")){
                spece = string.match(span.innerHTMl,
"(.*?)<")
               
break ;     
            }
        }
        
        clickLink(
"关闭")
        
return spece;   
     }  
   
}


//进入消息循环
win.loopMessage();
return winform,wb;


52

主题

1270

回帖

7276

积分

荣誉会员

积分
7276
 楼主| 发表于 2011-7-17 00:35:17 | 显示全部楼层
本帖最后由 qqmmcc 于 2011-8-2 12:23 编辑



四。程序发布

4.1 知识点

      程序调试完毕没问题后,可发布EXE文件给其他人使用,程序发布涉及知识下面的帖子已有很详尽的说明,这里不再复述了,具体内容可点击浏览。
      唯一注意的是配置文件lst放置位置,如果放在RES资源文件夹里,发布时会自动包含在EXE文件里,所以要放在非资源文件夹,发布时会自动把该文件COPY到发布目录,也可以放在其他文件夹,自己手动COPY打包压缩等。





4.2 示例发布EXE

120956lh4jb7dq7qqbbz48.png

12384661y233fhwhpokuhy.png

源码下载


115.rar (467.93 KB, 下载次数: 734)








  • 后缀:

       这是我第一个窗体程序,而且是父子窗体,从构思到完成,花了10多天时间,其中运行N个账户后换IP的算法就让我想了2天,没办法,数学差算法差,但写这个程序,每一天给都我有新的感觉和知识提升,很开心,觉得编程真是很有趣,所以希望各位同学多动手去学习;
       如lujjjh所言:“你不妨尝试着自己去完成一个目标,这比修改别人的代码来的有效的多,毕竟别人经历过和自己经历过是不一样的。这个不一定要一天完成,可能花一个月甚至更长,但是每天都有收获!”

看完此实例教程后,大家可吸收思路,然后把窗体练习---多账户事件操作 练习一遍,先记住不要参考他人的代码,到了万不得已时才看别人的代码,这样你的印象才深刻!

在写此软件时我自己碰到如下问题:大家也可以参考一下,
web子窗体如何接收父窗体传递来的数据
web函数怎么封装为自定义函数用户库
用户库函数返回值是调用主体程序的函数怎么写
combobox怎么在运行时自动获取默认值

并希望你们在提出问题时留意以下几点:
1.标题要清晰并且明确问题的重点,让他人能迅速了解你的问题所在;
2.提问内容尽可能清晰表达,不要吝惜打字,来龙去脉要清楚,不要让人费时间去猜测你的问题所在。
3..必要时贴图说出你想要的目的和问题,并尽可能将你遇到问题的代码单独抽离出来,并能独立运行,节约他人时间,也能让他人迅速帮你解决问题;

个人感觉,此程序代码写得还比较粗糙,欢迎指出不足之处,大家讨论,共同进步,谢谢!

祝大家有个aardio快乐之旅



3

主题

45

回帖

1126

积分

四级会员

积分
1126
发表于 2011-7-17 00:52:53 | 显示全部楼层
版主的细心和奉献精神值得学习。

75

主题

767

回帖

5045

积分

六级会员

The only one

积分
5045
发表于 2011-7-17 00:59:08 来自手机 | 显示全部楼层
qmc辛苦了!支持下!

7

主题

293

回帖

1900

积分

新手入门

积分
1900
QQ
发表于 2011-7-17 10:23:58 | 显示全部楼层
如此详尽的学习资料,足见楼主下了一番功夫,敬佩!学习ing.....

39

主题

163

回帖

1351

积分

四级会员

积分
1351
发表于 2011-7-17 10:38:05 | 显示全部楼层
我也来捧场咯,版主花了不少心思呀~赞一个{:soso_e179:}

9

主题

68

回帖

1001

积分

荣誉会员

积分
1001
发表于 2011-7-17 11:13:04 | 显示全部楼层
原创教程我一定要顶。

10

主题

52

回帖

326

积分

二级会员

积分
326
发表于 2011-7-17 11:40:21 | 显示全部楼层
不支持对不起自己!

48

主题

542

回帖

3328

积分

五级会员

积分
3328
发表于 2011-7-17 19:14:22 | 显示全部楼层
支持一下,感谢分享

13

主题

54

回帖

537

积分

三级会员

积分
537
发表于 2011-7-17 21:19:57 | 显示全部楼层
很不错。。 知识点很多。

5

主题

42

回帖

540

积分

三级会员

积分
540
发表于 2011-7-18 11:30:23 | 显示全部楼层
很好的帖子,受用了

2

主题

42

回帖

349

积分

二级会员

积分
349
发表于 2011-7-18 11:37:05 | 显示全部楼层
顶!感谢分享!

11

主题

41

回帖

493

积分

二级会员

积分
493
发表于 2011-7-22 08:20:17 | 显示全部楼层
谢谢给我们这么好的资料,节省了我们很多的时间,谢谢

11

主题

41

回帖

493

积分

二级会员

积分
493
发表于 2011-7-22 08:21:05 | 显示全部楼层
收藏一下,好东西不容错过

51

主题

212

回帖

1548

积分

四级会员

积分
1548
发表于 2011-7-22 22:03:39 | 显示全部楼层
{:soso_e114:}一个非常好非常全面的教程!
对新手是个非常好的教程。

2

主题

32

回帖

233

积分

二级会员

积分
233
发表于 2011-7-23 13:49:08 | 显示全部楼层
顶一下,呵呵增加知名度,好东西学习了
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

手机版|未经许可严禁引用或转载本站文章|aardio.com|aardio 官方社区 ( 皖ICP备09012014号 )

GMT+8, 2025-2-14 09:12 , Processed in 0.101094 second(s), 30 queries .

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表