快下班了,赶紧问个问题,多线程的。

sgyiliya 2013-07-24 05:08:29
我要访问一个视图,30秒刷一次,最近变慢了,在查询分析器里刷一次就要3-5秒,原先是0秒,导致程序每次访问视图的时候都卡住几秒,用户不爽。

我本来是用定时器来刷新的,现在想改用线程。看看能不能解决卡的问题。

在线程里面可以动态生成ADOQuery ,adoconn,这两个控件。

但是datasource怎么解决啊?因为读取视图返回的数据是要展现在主窗口类的一个表格控件里面,那么这个表格控件的datasource必须是使用主窗口类里面的现有的,不能是线程里动态生成的,那现在怎么办?

我能不能这样做,在线程类的头文件里,声明一个datasource控件,然后,在主窗口类里把一个现有的datasource控件拉到界面上来,接着在生成这个线程类对象的时候,把这个主窗口类的datasource控件作为一个参数传进去给这个线程类的构造函数呢?这个参数要用指针吗?

但是具体的代码怎么写?能不能大侠们帮我写写例子?

最后,我还想问个问题,我在主窗口类里面有个全局字符串变量比如GetView,这个字符串变量保存的就是访问视图的SQL语句,在程序运行的时候,用户可能会修改它的排序方式之类的,然后我要把这个字符串变量的修改让子线程能够知道,那又怎么办呢?在子线程的CPP文件里面用extern AnsiString GetView;这样就可以了吗?或者是要怎么解决呢?


诸多问题,敬请大侠们教导!!!最好给出代码例子。万分谢谢!
...全文
269 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
sgyiliya 2013-07-25
  • 打赏
  • 举报
回复
我写的视图很烂,还请大侠们费心看看。



SELECT     dbo.Today.Task AS TaskDescr, dbo.Today.No, dbo.Today.Downno, 
                      dbo.Today_2.time4 AS time4, dbo.Today.Via AS bypass, dbo.Today.Hos AS Hos, 
                      dbo.Today.time1 AS time1, dbo.Today.time2 AS time2, 
                      dbo.Today.time5 AS Time5, dbo.Today.time3 AS time3, 
                      dbo.Today.Area AS area, '出' AS io, dbo.Today.Status, 
                      CASE WHEN dbo.Today.ber < 0 THEN '' WHEN dbo.Today.ber IN (1) THEN '南' + CONVERT(varchar, 
                      dbo.Today.ber) WHEN dbo.Today.ber > 17 THEN '北' + CONVERT(varchar, dbo.Today.ber) 
                      ELSE CONVERT(varchar, dbo.Today.ber) END AS Ber, dbo.Today.Gate AS Gate, 
                      dbo.Today.Pla AS Pla, dbo.Today.type,  
                      dbo.Reason.ReasonCN AS DisplayReason, CASE WHEN ltrim(rtrim(dbo.Today.Memo)) = '' AND 
                      ltrim(rtrim(dbo.Today.StatMemo)) <> '' THEN dbo.TodayD.StatMemo WHEN ltrim(rtrim(dbo.Today.Memo)) 
                      <> '' AND ltrim(rtrim(dbo.Today.StatMemo)) 
                      = '' THEN dbo.Today.Memo WHEN ltrim(rtrim(dbo.Todays.Memo)) <> '' AND 
                      ltrim(rtrim(dbo.Today.StatMemo)) 
                      <> '' THEN dbo.Today.Memo + ',' + dbo.Today.StatMemo WHEN ltrim(rtrim(dbo.Today.Memo)) = '' AND
                       ltrim(rtrim(dbo.Today.StatMemo)) = '' THEN '' END AS Remark, ISNULL(dbo.f_MergeVipName(dbo.Today.No, 
                      N'出', dbo.Today.Opday), N'') AS vipinfo, dbo.Today.lines
FROM         dbo.Today LEFT OUTER JOIN
                      dbo.Reason ON dbo.Today.PublishReason = dbo.Reason.ReasonID LEFT OUTER JOIN
                      dbo.Today_2 ON dbo.Today.Downno = dbo.Today_2.no
WHERE     (dbo.Today.Task NOT IN ('货A', '货B'))


这里的dbo.Today和dbo.Today_2都分别只有100多条的记录。字段也差不多都是35个。dbo.Reason里面是31条记录,6个字段。 可能关键是dbo.Today和dbo.Today_2,因为他们的数据是别的存储过程或者客户端实时写进来更新的。 dbo.f_MergeVipName,这个函数如下: set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER function [dbo].[f_MergeVipName](@no nvarchar(20),@Io nvarchar(20),@Opday Datetime) returns nvarchar(Max) as begin declare @r nvarchar(Max) set @r='' select @r=@r+';'+( Name+','+ Class) from Vip where no=@no and Io = @Io and [Date]=@opday return stuff(@r,1,1,'') end 会不会是视图里面的memo判断导致的?还是这个dbo.f_MergeVipName函数导致的? 若是函数导致的,我测试了select Name+','+ Class as test from Vip where no like '%%' and Io = '出' and [Date]='2013-07-25',执行时间是0秒。 这个VIP表里有2万条记录,但是每天的记录也就10几条,很少的。
sgyiliya 2013-07-25
  • 打赏
  • 举报
回复



我写的视图很烂,还请大侠们费心看看。



SELECT     dbo.Today.Task AS TaskDescr, dbo.Today.No, dbo.Today.Downno, 
                      dbo.Today_2.time4 AS time4, dbo.Today.Via AS bypass, dbo.Today.Hos AS Hos, 
                      dbo.Today.time1 AS time1, dbo.Today.time2 AS time2, 
                      dbo.Today.time5 AS Time5, dbo.Today.time3 AS time3, 
                      dbo.Today.Area AS area, '出' AS io, dbo.Today.Status, 
                      CASE WHEN dbo.Today.ber < 0 THEN '' WHEN dbo.Today.ber IN (1) THEN '南' + CONVERT(varchar, 
                      dbo.Today.ber) WHEN dbo.Today.ber > 17 THEN '北' + CONVERT(varchar, dbo.Today.ber) 
                      ELSE CONVERT(varchar, dbo.Today.ber) END AS Ber, dbo.Today.Gate AS Gate, 
                      dbo.Today.Pla AS Pla, dbo.Today.type,  
                      dbo.Reason.ReasonCN AS DisplayReason, CASE WHEN ltrim(rtrim(dbo.Today.Memo)) = '' AND 
                      ltrim(rtrim(dbo.Today.StatMemo)) <> '' THEN dbo.TodayD.StatMemo WHEN ltrim(rtrim(dbo.Today.Memo)) 
                      <> '' AND ltrim(rtrim(dbo.Today.StatMemo)) 
                      = '' THEN dbo.Today.Memo WHEN ltrim(rtrim(dbo.Todays.Memo)) <> '' AND 
                      ltrim(rtrim(dbo.Today.StatMemo)) 
                      <> '' THEN dbo.Today.Memo + ',' + dbo.Today.StatMemo WHEN ltrim(rtrim(dbo.Today.Memo)) = '' AND
                       ltrim(rtrim(dbo.Today.StatMemo)) = '' THEN '' END AS Remark, ISNULL(dbo.f_MergeVipName(dbo.Today.No, 
                      N'出', dbo.Today.Opday), N'') AS vipinfo, dbo.Today.lines
FROM         dbo.Today LEFT OUTER JOIN
                      dbo.Reason ON dbo.Today.PublishReason = dbo.Reason.ReasonID LEFT OUTER JOIN
                      dbo.Today_2 ON dbo.Today.Downno = dbo.Today_2.no
WHERE     (dbo.Today.Task NOT IN ('货A', '货B'))


这里的dbo.Today和dbo.Today_2都分别只有100多条的记录。字段也差不多都是35个。dbo.Reason里面是31条记录,6个字段。
可能关键是dbo.Today和dbo.Today_2,因为他们的数据是别的存储过程或者客户端实时写进来更新的。


dbo.f_MergeVipName,这个函数如下:


set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

ALTER function [dbo].[f_MergeVipName](@no nvarchar(20),@Io nvarchar(20),@Opday Datetime)
returns nvarchar(Max)
as
begin
declare @r nvarchar(Max)
set @r=''

select @r=@r+';'+( Name+','+ Class) from Vip where no=@no and Io = @Io and [Date]=@opday

return stuff(@r,1,1,'')
end



会不会是视图里面的memo判断导致的?还是这个dbo.f_MergeVipName函数导致的?


若是函数导致的,我测试了select Name+','+ Class as test from Vip where no like '%%' and Io = '出' and [Date]='2013-07-25',执行时间是0秒。
这个VIP表里有2万条记录,但是每天的记录也就10几条,很少的。









sgyiliya 2013-07-25
  • 打赏
  • 举报
回复
引用 14 楼 fbmsyu 的回复:
把视图代码贴上来看看。
我写的视图很烂,还请大侠们费心看看。 SELECT dbo.Today.Task AS TaskDescr, dbo.Today.No, dbo.Today.Downno, dbo.Today_2.time4 AS time4, dbo.Today.Via AS bypass, dbo.Today.Hos AS Hos, dbo.Today.time1 AS time1, dbo.Today.time2 AS time2, dbo.Today.time5 AS Time5, dbo.Today.time3 AS time3, dbo.Today.Area AS area, '出' AS io, dbo.Today.Status, CASE WHEN dbo.Today.ber < 0 THEN '' WHEN dbo.Today.ber IN (1) THEN '南' + CONVERT(varchar, dbo.Today.ber) WHEN dbo.Today.ber > 17 THEN '北' + CONVERT(varchar, dbo.Today.ber) ELSE CONVERT(varchar, dbo.Today.ber) END AS Ber, dbo.Today.Gate AS Gate, dbo.Today.Pla AS Pla, dbo.Today.type, dbo.Reason.ReasonCN AS DisplayReason, CASE WHEN ltrim(rtrim(dbo.Today.Memo)) = '' AND ltrim(rtrim(dbo.Today.StatMemo)) <> '' THEN dbo.TodayD.StatMemo WHEN ltrim(rtrim(dbo.Today.Memo)) <> '' AND ltrim(rtrim(dbo.Today.StatMemo)) = '' THEN dbo.Today.Memo WHEN ltrim(rtrim(dbo.Todays.Memo)) <> '' AND ltrim(rtrim(dbo.Today.StatMemo)) <> '' THEN dbo.Today.Memo + ',' + dbo.Today.StatMemo WHEN ltrim(rtrim(dbo.Today.Memo)) = '' AND ltrim(rtrim(dbo.Today.StatMemo)) = '' THEN '' END AS Remark, ISNULL(dbo.f_MergeVipName(dbo.Today.No, N'出', dbo.Today.Opday), N'') AS vipinfo, dbo.Today.lines FROM dbo.Today LEFT OUTER JOIN dbo.Reason ON dbo.Today.PublishReason = dbo.Reason.ReasonID LEFT OUTER JOIN dbo.Today_2 ON dbo.Today.Downno = dbo.Today_2.no WHERE (dbo.Today.Task NOT IN ('货A', '货B')) 这里的dbo.Today和dbo.Today_2都分别只有100多条的记录。字段也差不多都是35个。dbo.Reason里面是31条记录,6个字段。 可能关键是dbo.Today和dbo.Today_2,因为他们的数据是别的存储过程或者客户端实时写进来更新的。 dbo.f_MergeVipName,这个函数如下: set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER function [dbo].[f_MergeVipName](@no nvarchar(20),@Io nvarchar(20),@Opday Datetime) returns nvarchar(Max) as begin declare @r nvarchar(Max) set @r='' select @r=@r+';'+( Name+','+ Class) from Vip where no=@no and Io = @Io and [Date]=@opday return stuff(@r,1,1,'') end 会不会是视图里面的memo判断导致的?还是这个dbo.f_MergeVipName函数导致的? 若是函数导致的,我测试了select Name+','+ Class as test from Vip where no like '%%' and Io = '出' and [Date]='2013-07-25',执行时间是0秒。 这个VIP表里有2万条记录,但是每天的记录也就10几条,很少的。
缘中人 2013-07-25
  • 打赏
  • 举报
回复
你的查询分析器是在客户端还是在服务器上执行,有没有可能是网络的原因 视图也就是SQL语句,你直接执行SQL语句是多长时间
fbmsyu 2013-07-25
  • 打赏
  • 举报
回复
把视图代码贴上来看看。
sgyiliya 2013-07-25
  • 打赏
  • 举报
回复
3,3,1,2,3,0,2,2,3,3(10次结果,单位秒) 2,3,5,4,2,3,2,4,5,3(10次结果,单位秒) 就这两个视图,视图的语句都没有任何变化,我记得原先10次都基本是0秒的。 我查不出原因,他们也查不出原因,硬说是我的问题。我奈何。无可奈何。
sgyiliya 2013-07-25
  • 打赏
  • 举报
回复
也就18个字段,100多条数据。居然也要3-5秒。没办法,无语。
缘中人 2013-07-25
  • 打赏
  • 举报
回复
有100多条数据,查询分析器里刷一次就要3-5秒,原先是0秒 我觉得这个原因你得查
sgyiliya 2013-07-25
  • 打赏
  • 举报
回复
引用 9 楼 ksrsoft 的回复:
再者,你查询数据,也不一定要全部显示出来吧 View_Ter_In_20130708 是不是加个条件过滤少展示一些数据,如果数据无限大,必然越来越慢。。。。
不多啊,就只有100多条数据啊,唉呀,数据库索引如何优化我又不懂,气死我了,硬说是我的问题。
缘中人 2013-07-25
  • 打赏
  • 举报
回复
再者,你查询数据,也不一定要全部显示出来吧 View_Ter_In_20130708 是不是加个条件过滤少展示一些数据,如果数据无限大,必然越来越慢。。。。
缘中人 2013-07-25
  • 打赏
  • 举报
回复
查询分析器里刷一次就要3-5秒,原先是0秒 ------------------- 视图的SQL语句是否要优化,数据库的索引是否要调整,数据库层的要先处理好
lhy 2013-07-25
  • 打赏
  • 举报
回复
访问数据库的部分全都放到一个线程里。
ccrun.com 2013-07-25
  • 打赏
  • 举报
回复
引用 12 楼 sgyiliya 的回复:
也就18个字段,100多条数据。居然也要3-5秒。没办法,无语。
你的线程单元我已帮你改好,一会收邮件。
sgyiliya 2013-07-24
  • 打赏
  • 举报
回复
妖哥,我已经打包好了,已经发送给您的邮箱,太感谢您了!
ccrun.com 2013-07-24
  • 打赏
  • 举报
回复
你把你的demo工程压缩一下发我信箱,我帮你调试一下。 cbfans at 163 dot com
sgyiliya 2013-07-24
  • 打赏
  • 举报
回复
妖哥,把程序又改了,现在最新的情况是,主窗口的两个表格都可以看见了,表格里的列也都出来了,程序也不会卡死了,但是表格里面没有任何数据,就是没有办法得到刷新的数据,实在是没办法了。 妖哥请帮忙啊! 最新代码如下。因为连续3个回复了,没办法再回复了,待会马上另开一贴,再请妖哥帮忙啊!

__fastcall TGetView::TGetView(bool CreateSuspended,TADOQuery * ADOQ_Post_Out,TADOQuery * ADOQ_Post_In)
        : TThread(CreateSuspended)
{
        ADOConn = new TADOConnection(NULL);
        ADOConn->ConnectionString = AnsiString("Provider=SQLOLEDB.1;Password=801;\
Persist Security Info=True;Auto Translate=false;\
User ID=sa;\
Initial Catalog=New;\
Data Source=192.168.226.5");
        ADOConn->ConnectionTimeout = 600;
        ADOConn->CommandTimeout = 600;
        ADOConn->KeepConnection = false;
        ADOConn->LoginPrompt = false;
 
        ADOQ_Get_View_Out = new TADOQuery(NULL);
        ADOQ_Get_View_Out->Connection = ADOConn;
        ADOQ_Get_View_Out->CommandTimeout = 600;
 
        ADOQ_Get_View_In = new TADOQuery(NULL);
        ADOQ_Get_View_In->Connection = ADOConn;
        ADOQ_Get_View_In->CommandTimeout = 600;

        ADOQ_Get_View_Out = ADOQ_Post_Out;
        ADOQ_Get_View_In = ADOQ_Post_In;

        Out = AnsiString( "Select * from View_Ter_Out_20130708");
        In = AnsiString("Select *  from View_Ter_In_20130708");
}
//---------------------------------------------------------------------------
void __fastcall TGetView::Execute()
{
        //---- Place thread code here ----
        CoInitialize(NULL);
        ADOConn->Connected = true;
        Synchronize(MyExe);
        CoUninitialize();
}
//---------------------------------------------------------------------------
void __fastcall TGetView::MyExe()
{

        while( !Suspended || !Terminated )
        {
                ADOQ_Get_View_Out->Close();
                ADOQ_Get_View_Out->SQL->Clear();
                ADOQ_Get_View_Out->SQL->Add(Out);
                ADOQ_Get_View_Out->Open();
 
                ADOQ_Get_View_In->Close();
                ADOQ_Get_View_In->SQL->Clear();
                ADOQ_Get_View_In->SQL->Add(In);
                ADOQ_Get_View_In->Open();

                ::Sleep(30000);
        }

}

sgyiliya 2013-07-24
  • 打赏
  • 举报
回复
妖哥,刚刚把程序又改了。 现在是这样的,在DM模块里拉了两个DataSource控件:DM->DataSource_Ter_Out,DM->DataSource_Ter_In 然后把主窗口类里面的两个表格控件的DataSource属性设置为:DM->DataSource_Ter_Out,DM->DataSource_Ter_In,然后在DM模块里再拉了两个TADOQuery控件:DM->ADOQ_Ter_Out,DM->ADOQ_Ter_In, 然后把DM->DataSource_Ter_Out的DataSet设置为DM->ADOQ_Ter_Out,把DM->DataSource_Ter_In的DataSet设置为DM->ADOQ_Ter_In,再把DM->ADOQ_Ter_Out,DM->ADOQ_Ter_In,两个控件的Connection属性和SQL属性也设置好了,DM模块里面的TADOConnection控件也拉进来了,设置好连接了。主窗口的两个表格控件的字段都加好了,把两个TADOQuery控件激活后,在设计环境下就可以看到表格里面就有数据了。 然后在FormShow里面这样:把现成的两个TADOQuery控件传递进去。 Thread_GetView = new TGetView(false,DM->ADOQ_Ter_Out,DM->ADOQ_Ter_In); 主窗口类的头文件里声明了:TGetView * Thread_GetView; 最后,刷新视图的线程类修改为如下:

__fastcall TGetView::TGetView(bool CreateSuspended,TADOQuery * ADOQ_Post_Out,TADOQuery * ADOQ_Post_In)
        : TThread(CreateSuspended)
{
        ADOQ_Get_View_Out = ADOQ_Post_Out;

        ADOQ_Get_View_In = ADOQ_Post_In;
}
//---------------------------------------------------------------------------
void __fastcall TGetView::Execute()
{
        //---- Place thread code here ----
        Synchronize(MyExe);
}
//---------------------------------------------------------------------------
void __fastcall TGetView::MyExe()
{
        CoInitialize(NULL);
        while( !Suspended || !Terminated )
        {
                ADOQ_Get_View_Out->Close();
                ADOQ_Get_View_Out->Open();

                ADOQ_Get_View_In->Close();
                ADOQ_Get_View_In->Open();

                ::Sleep(30000);
        }
        CoUninitialize();
}


//线程类的头文件:

#ifndef Unit_GetViewH
#define Unit_GetViewH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <ADODB.hpp>
#include <DB.hpp>
//---------------------------------------------------------------------------
class TGetView : public TThread
{            
private:
protected:
        void __fastcall Execute();
public:
        __fastcall TGetView(bool CreateSuspended,TADOQuery * ADOQ_Post_Out,TADOQuery * ADOQ_Post_In);
        TADOQuery * ADOQ_Get_View_Out;
        TADOQuery * ADOQ_Get_View_In;
        void __fastcall MyExe();
};
但是还是不行,程序进去了,但是主窗口的表格都看不见了,出不来,然后马上整个界面就白了,程序卡死了,又没有弹出出错框,只好杀了进程,程序无法执行。 故障完全一样。 请妖哥帮忙啊!
sgyiliya 2013-07-24
  • 打赏
  • 举报
回复
妖哥,真是太感谢您了。真是希望您能再帮我看看代码。现在是界面的数据出不来,程序卡死,无法运行。 估计还是datasource的问题,麻烦您看看。 刷新视图的线程类:

__fastcall TGetView::TGetView(bool CreateSuspended,TDataSource *DataSource_Post_Out,TDataSource *DataSource_Post_In)
        : TThread(CreateSuspended)
{
        ADOConn = new TADOConnection(NULL);
        ADOConn->ConnectionString = AnsiString("Provider=SQLOLEDB.1;Password=801;\
Persist Security Info=True;Auto Translate=false;\
User ID=sa;\
Initial Catalog=New;\
Data Source=192.168.226.5");
        ADOConn->ConnectionTimeout = 600;
        ADOConn->CommandTimeout = 600;
        ADOConn->KeepConnection = false;
        ADOConn->LoginPrompt = false;

        DataSource_Out = DataSource_Post_Out;
        DataSource_In = DataSource_Post_In;

        ADOQ_Get_View_Out = new TADOQuery(NULL);
        ADOQ_Get_View_Out->Connection = ADOConn;
        ADOQ_Get_View_Out->CommandTimeout = 600;

        ADOQ_Get_View_In = new TADOQuery(NULL);
        ADOQ_Get_View_In->Connection = ADOConn;
        ADOQ_Get_View_In->CommandTimeout = 600;

        DataSource_Out->DataSet = ADOQ_Get_View_Out;
        DataSource_In->DataSet = ADOQ_Get_View_In;

        Out = AnsiString( "Select * from View_Ter_Out_20130708");

        In = AnsiString("Select *  from View_Ter_In_20130708");

}
//---------------------------------------------------------------------------
void __fastcall TGetView::Execute()
{
        //---- Place thread code here ----
        Synchronize(MyExe);
}
//---------------------------------------------------------------------------
void __fastcall TGetView::MyExe()
{
        CoInitialize(NULL);
        ADOConn->Connected = true;
        while( !Suspended || !Terminated )
        {
                ADOQ_Get_View_Out->Close();
                ADOQ_Get_View_Out->SQL->Clear();
                ADOQ_Get_View_Out->SQL->Add(Out);
                ADOQ_Get_View_Out->Open();

                ADOQ_Get_View_In->Close();
                ADOQ_Get_View_In->SQL->Clear();
                ADOQ_Get_View_In->SQL->Add(In);
                ADOQ_Get_View_In->Open();

                ::Sleep(30000);
        }
        CoUninitialize();
}

//线程类的头文件:


#ifndef Unit_GetViewH
#define Unit_GetViewH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <ADODB.hpp>
#include <DB.hpp>
//---------------------------------------------------------------------------
class TGetView : public TThread
{            
private:
protected:
        void __fastcall Execute();
public:
        __fastcall TGetView(bool CreateSuspended,TDataSource *DataSource_Post_Out,TDataSource *DataSource_Post_In);
        TADOQuery * ADOQ_Get_View_Out;
        TADOQuery * ADOQ_Get_View_In;
        TADOConnection *ADOConn;
        TDataSource *DataSource_Out;
        TDataSource *DataSource_In;
        AnsiString Out,In;
        void __fastcall MyExe();
};

然后,在DM模块里拉了两个DataSource控件:DM->DataSource_Ter_Out,DM->DataSource_Ter_In 然后把主窗口类里面的两个表格控件的DataSource属性设置为:DM->DataSource_Ter_Out,DM->DataSource_Ter_In 接着在主窗口类的FormShow里面: Thread_GetView = new TGetView(false,DM->DataSource_Ter_Out,DM->DataSource_Ter_In); 主窗口类的头文件里声明了:TGetView * Thread_GetView; 现在情况是这样子,程序进去了,但是主窗口的表格都看不见了,出不来,然后马上整个界面就白了,程序卡死了,又没有弹出出错框,只好杀了进程,程序无法执行。 求求妖哥帮忙啊!
ccrun.com 2013-07-24
  • 打赏
  • 举报
回复
线程中操作VCL对象,用Thread向导建议的Synchronize方法

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧