首页 > 代码库 > ERS遇到的问题及solution
ERS遇到的问题及solution
1, js事件响应函数在firefox/safari中正确的设置
错误:a.onclick=function(){......};
正确:a.setAttribute("onclick","....");
2, VS中文件内容的批量替换
查找和替换中:勾选“正则表达式”选项
【示例: 替换onclick事件的绑定】
onclick ={(.+)}(";)$ -----> setAttribute("onclick", \1");
其中\1在VS表示第一个打标记的匹配,即{}部分
3, 浏览器兼容性
① firefox不支持innerText
② firefox对event的处理,event是IE对页面事件的封装
function $getEvent() {
if (window.event) {
return window.event;
}
var caller = $getEvent.caller;
while (caller !== null) {
var argument = caller.arguments[0];
if (argument) {
var temp = argument.constructor;
if (temp.toString().indexOf("Event") != -1) {
return argument;
}
}
caller = caller.caller;
}
return null;
}
function $getTarget() {
var e = $getEvent();
return e.srcElement || e.target;
}
function $getKeyCode() {
var e = $getEvent();
return e.keyCode || e.which;
}
3,linkbotton在chorme/safari下渲染成a标签,所以点击事件要从
mainLbtn.click();
改为
window.document.location=$(mainLbtn).attr("href");
或者把linkBotton改成button
3.5 对于链接过的页面,可以再JS中window.opener.document.getElementById("pre_id") 找到前一页面的控件
4, ajax无刷新上传文件,返回Json数据时,safari会生成多余标签,要用正则取出{....}字符串
5,Telerik配置错误,修改web.cinfig
① system.webServer节点的handlers中增加下面两句
<system.webServer>
<handlers>
<add name="Telerik_Web_UI_WebResource_axd" verb="*" preCondition="integratedMode" path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource"/>
<add name="Telerik_Web_UI_DialogHandler_aspx" verb="*" preCondition="integratedMode" path="Telerik.Web.UI.DialogHandler.aspx" type="Telerik.Web.UI.DialogHandler"/>
</handlers>
</system.webServer>
② system.web节点的httpHandlers中增加如下
<httpHandlers>
<add verb="*" path="Telerik.RadUploadProgressHandler.ashx" type="Telerik.Web.UI.Upload.RadUploadProgressHandler, Telerik.Web.UI"/>
<add verb="*" path="Telerik.Web.UI.SpellCheckHandler.axd" type="Telerik.Web.UI.SpellCheckHandler, Telerik.Web.UI, Culture=neutral, PublicKeyToken=121fae78165ba3d4"/>
<add path="Telerik.Web.UI.WebResource.axd" verb="*" type="Telerik.Web.UI.WebResource, Telerik.Web.UI" validate="false"/>
<add path="Telerik.Web.UI.DialogHandler.aspx" type="Telerik.Web.UI.DialogHandler" verb="*" validate="false"/>
</httpHandlers>
6, Telerik中gridview导出Excel文件时数字编码会有Num格式088212111222190414---888E什么的
【】 在ItemDataBound方法中
if (e.Item is GridDataItem)
{
//。。。。。
GridDataItem dataItem = e.Item as GridDataItem;
dataItem["ApplicationNo"].Attributes.Add("style", "vnd.ms-excel.numberformat:@");
dataItem["Amount"].Attributes.Add("style", "vnd.ms-excel.numberformat:0.00");
//。。。。。
}
7, wcf不支持 重载
同名方法名称即使参数不一致,仍会当成一个方法处理。。。。
8, ERS项目里所有的方法都在一个接口的定义,然后很多业务上的方法分文件部分类实现它
9, IE快捷键:
清此域缓存:F12,ctrl+D,Alt+F4
10,VS2010常用快捷键:
F12
ctrl+‘-‘
Ctrl+W,S: 解决方案管理器
Ctrl+W,P: 属性窗口
Ctrl+D,B: 断点窗口
Ctrl+D,I: 即时窗口
Ctrl+Tab: 活动窗体切换
Ctrl+E,C / Ctrl+K,C: 注释选定内容
Ctrl+E,U / Ctrl+K,U: 取消选定注释内容
Ctrl+W,X: 工具箱
Ctrl+W,O: 输出视图
11,一个系统中一般会有很多无关的流程,但一般流程详细步骤一般都放在一张表中,所以系统运行一段时候后,这个表将会非常大,查询很慢慢。好像在相互牵制。所以流程最好要分表,
12,
①默认的是InProc
②可以选择为StateServer,是保存在服务器中的状态服务中,可已在管理工具-->服务 中查看
③将Session保存到SQL Server中,需要有以下几个步骤:
1.首先要创建用于保存Session数据的数据库,以命令行的形式用aspnet_regsql.exe来完成,具体命令为 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regsql.exe -ssadd -sstype c -d sd -E
该命令是以windows验证方式,添加了sd数据库保存session数据。
2.需要修改ASP.NET web.config文件中的SessionState结点,该结点位于<system.web>下
<sessionState mode="SQLServer" allowCustomSqlDatabase="true"
sqlConnectionString="server=.;uid=sa;password=;initial catalog=sd"
cookieless="false"
timeout="20">
</sessionState>
这样一来,Session数据就不再是依赖于IIS进程而是保存到数据库中。可以打开sd数据库会有两个表分别为ASPStateTempSessions、ASPStateTempApplications。
13, excel 03版本的话 6万多条就爆听说
14,SSIS包数据源的参数在“包资源管理器”--“连接管理器”,单击数据源,在Expressions中添加ConnectionString中写“@[User::ParameterName]”
15, 均衡分单,人不在岗不给
16,
① 了解System.Web.UI.HtmlTextWriterStyle类
public static string ShowOrHideControl(bool visible, System.Web.UI.WebControls.WebControl controlID)
{
return controlID.Style[System.Web.UI.HtmlTextWriterStyle.Display] = visible ? "" : "None";
}
public static string ShowOrHideControl(bool visible, System.Web.UI.HtmlControls.HtmlControl controlID)
{
return controlID.Style[System.Web.UI.HtmlTextWriterStyle.Display] = visible ? "" : "None";
}
② txtAmount.Style.Add("background-color", "#eee");
③ drSel.Attributes["onchange"] = string.Format("AllowanceItemsProxy.ReCalculateAllowanceDay(‘{0}‘);", rpItem.ItemIndex);
17, 在生成的类的头文件引用前加版权之类的信息:
VS2010 中找到(安装盘符以D盘为例)D:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplatesCache\CSharp\Code\2052\Class.zip
在Class.cs文件顶部加入 注释格式的描绘就可以了
18,流程分表、定期重建索引的Job
19, js中的date是客户端的时间,很多时候我们需要用服务端的时间,所以可以在ClientBase.js中写一个取服务端时间的方法
var CacheProxy = new ClientCacheManager(‘default‘);
var __serverDateTime = new Date(Date.parse(‘<%=System.DateTime.Now.ToString() %>‘));
CacheProxy.set_cache(‘ServerDateTime‘, __serverDateTime);
---------------
t.GetServerDateTime = function () {
if (t._serverDateTime == null) {
var cachedDate = CacheProxy.get_cache(‘ServerDateTime‘);
if (cachedDate == null) {
t._serverDateTime = new Date();
} else {
t._serverDateTime = cachedDate;
}
}
return t._serverDateTime;
};
---------------
var ClientCacheManager = function (name) {
var _cache = new Object();
_cache._name = name;
_cache._innerCache = new Array(0);
_cache.get_name = function () { return _cache._name; };
_cache.set_cache = function (key, obj) {
var cache;
for (var i = 0; i < _cache._innerCache.length; i++) {
cache = _cache._innerCache[i];
if (cache.get_key() == key) {
cache.set_value(obj);
return;
}
}
_cache._innerCache.push(new CacheObject(key, obj));
};
_cache.get_cache = function (key) {
var cache;
for (var i = 0; i < _cache._innerCache.length; i++) {
cache = _cache._innerCache[i];
if (cache.get_key() == key) {
return cache.get_value();
}
}
return null;
};
return _cache;
}
20, 一些常用字符串不妨定义为const,方便修改以及避免拼写错误。
21, 对于可空类型,GetValueOrDefault()是个很不错的习惯。。。
22,调试技巧
23
this.moreApprover.Style[HtmlTextWriterStyle.Display] = "none";
24, sql中匹配
declare @name nvarchar(1000) =N‘中国‘
select
case when PATINDEX(‘%[A-Za-z]%‘,@name)<=0 then ‘中国‘
else ‘老外‘ end
25 update from & update join
declare @t1 table(
cwid nvarchar(5),
name nvarchar(20)
)
declare @t2 table(
cwid nvarchar(5),
name nvarchar(20)
)
insert into @t1 (cwid,name) values(‘chxhi‘,‘bb‘)
insert into @t1 (cwid,name) values(‘chigg‘,‘cc‘)
insert into @t1 (cwid,name) values(‘chddx‘,‘dd‘)
insert into @t2 (cwid,name) values(‘chxhi‘,‘11‘)
insert into @t2 (cwid,name) values(‘chigg‘,‘22‘)
insert into @t2 (cwid,name) values(‘chddd‘,‘33‘)
select * from @t2
update t2
set name=t1.name
from @T2 t2
inner join
@T1 t1 on t1.cwid=t2.cwid
select * from @t2
26, 用union,从功能上讲就没必要每句再加distinct
declare @t1 table
(
id int,
name nvarchar(30),
age int
)
declare @t2 table
(
id int,
name nvarchar(30),
age int
)
insert into @t1 (id,name,age) values(1,‘aaa‘,7)
insert into @t1 (id,name,age) values(2,‘bbb‘,6)
insert into @t1 (id,name,age) values(3,‘ccc‘,8)
insert into @t1 (id,name,age) values(3,‘ddd‘,8)
insert into @t2(id ,name,age) select id,name,age from @t1
select id from @t1
union
select ID from @t2
27, CSS自动换行
style="word-wrap: break-word;word-break:break-all"
28, edmx模型下执行sp
public DataSet GetMyParticipatedRequest(int EID, string CompanyCode, string RequestCategory, int? RequestTypeID, int? Requester, int? Submitter, int? ProcessStatus, int? PaidStatus, string ApplicationNo, DateTime? RequestDateFrom, DateTime? RequestDateTo, DateTime? CompleteDateFrom, DateTime? CompleteDateTo,
string RequestAmountFromType, string RequestAmountToType, decimal? RequestAmountFromValue, decimal? RequestAmountToValue,int? businessID, string OrderField,
ref int RowsCount, int? FirstRowNo, int? TakeCount)
{
string sp = "BP_ERS_GetMyParticipatedRequest";
List<SqlParameter> ObjectParameters = new List<SqlParameter>();
ObjectParameters.Add(new SqlParameter("@EID", EID));
if (CompanyCode == null)
ObjectParameters.Add(new SqlParameter("@CompanyCode", DBNull.Value));
else
ObjectParameters.Add(new SqlParameter("@CompanyCode", CompanyCode));
ObjectParameters.Add(new SqlParameter("@FirstRowNo", GetNull(FirstRowNo)));
if (TakeCount != null)
{
ObjectParameters.Add(new SqlParameter("@TakeCount", TakeCount));
}
else
{
ObjectParameters.Add(new SqlParameter("@TakeCount", 0));
}
ObjectParameters.Add(new SqlParameter("@RowsCount", SqlDbType.Int) { Direction = ParameterDirection.Output });
//List<BusinessInfomation> list= Context.ExecuteToList<BusinessInfomation>(sp, ObjectParameters.ToArray());
DataSet ds = this.Context.QueryToDataSet(sp, CommandType.StoredProcedure, ObjectParameters.ToArray());
RowsCount = int.Parse(ObjectParameters[21].Value.ToString());
return ds;
}
29, linq join / ling from
var UPRTag = from up in UserPositionRelationListTag
join e in employeeNoBHC
on up.EID equals e.EID
select up;
var queryBO = from pr in ppRoleListA1
from up in UPRTag
where (pr.PositionID==up.PositionID)
select pr.PRoleCode ?? string.Empty;
30, app_code文件夹下的文件, 属性要给成“编译”否则当成文本
-------------- LUMP Part-----------------------------------------------------------------------
31, 注册事件的应用场所 :MasterPage 中的公共控件在子页面中注册
32, 生成单号
-- =============================================
-- Author: Kevin Lai
-- Create date: 2010-9-7
-- Description:
-- Modified By Ethan 2011-10-31
-- =============================================
CREATE PROCEDURE [dbo].[BP_GetIndexCounterValue]
@CounterName NVARCHAR(50)
AS
BEGIN
DECLARE @CounterValue INT
insert TCFG_IndexCounter
select @CounterName,0,GETDATE()
where not exists( select CounterKey from TCFG_IndexCounter where CounterKey=@CounterName)
UPDATE TCFG_IndexCounter
SET CounterValue=http://www.mamicode.com/CounterValue+1,@CounterValue=CounterValue+1 ,LastModifyTime=GETDATE()
WHERE CounterKey=@CounterName
SELECT @CounterValue
RETURN @CounterValue
END
go
33, 用了telerik 后台弹窗就要用它的弹窗方法radAjax.ResponseScripts.Add("alert(‘22‘);");
34,前台js进不去一般可能是少了{ 之类的
35, $get(‘<%=this.ccIDHid.ClientID %>‘).style.display
36, 表为自增主键,特定主键的插入
set identity_insert T on
insert into T (id ,name) values(2,‘dd‘)
set identity_insert T off
----------------------
37, row_number() over(partition by c1 order by c2)
语法形式:ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2)
解释:根据COL1分组,在分组内部根据 COL2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的)
--1.创建测试表
create table #score
(
name varchar(20),
subject varchar(20),
score int
)
--2.插入测试数据
insert into #score(name,subject,score) values(‘张三‘,‘语文‘,98)
insert into #score(name,subject,score) values(‘张三‘,‘数学‘,80)
insert into #score(name,subject,score) values(‘张三‘,‘英语‘,90)
insert into #score(name,subject,score) values(‘李四‘,‘语文‘,88)
insert into #score(name,subject,score) values(‘李四‘,‘数学‘,86)
insert into #score(name,subject,score) values(‘李四‘,‘英语‘,88)
insert into #score(name,subject,score) values(‘李明‘,‘语文‘,60)
insert into #score(name,subject,score) values(‘李明‘,‘数学‘,86)
insert into #score(name,subject,score) values(‘李明‘,‘英语‘,88)
insert into #score(name,subject,score) values(‘林风‘,‘语文‘,74)
insert into #score(name,subject,score) values(‘林风‘,‘数学‘,99)
insert into #score(name,subject,score) values(‘林风‘,‘英语‘,59)
insert into #score(name,subject,score) values(‘严明‘,‘英语‘,96)
--3.取每个学科的前3名数据
select * from
(
select subject,name,score,row_number() over(PARTITION by subject order by score desc) as num
from #score
) T where T.num <= 3 order by subject
--4.删除临时表
truncate table #score
drop table #score
--------------------------------------------
38, 选择列的不同,使用的索引也不同,因为不同的索引返回的列也不同
39, 大量的主数据脚本可以用Excel拼出来
例如
="INSERT INTO [TCFG_LUMP_TimeZone] ([Year],[Month],[YearMonth],[Quarter],[From],[To]) values (‘"&A3&"‘,‘"&B3&"‘,‘"&C3&"‘,‘"&D3&"‘,‘"&E3&"‘,‘"&F3&"‘)"
40,类里面的int类型时分配在堆上
41
set nocount on;
declare @T1 table
(
ID int identity(0,1),
FirstName nvarchar(30),
CWID varchar(10)
)
declare @T2 table
(
ID int identity(0,1),
FirstName nvarchar(30),
CWID varchar(10)
)
insert into @T1 (FirstName,CWID) values(‘Lee‘,‘CHXHI‘)
insert into @T1 (FirstName,CWID) values(‘ROCK‘,‘EWERB‘)
insert into @T1 (FirstName,CWID) values(‘LINKIN‘,‘CHXXX‘)
insert into @T1 (FirstName,CWID) values(‘JIANG‘,‘CHQAA‘)
insert into @T1 (FirstName,CWID) values(‘TAYLEN‘,‘CHPEE‘)
insert into @T2 (CWID) values(‘CHXHI‘)
insert into @T2 (CWID) values(‘EWERB‘)
insert into @T2 (CWID) values(‘CHXXX‘)
insert into @T2 (CWID) values(‘CHQAA‘)
insert into @T2 (CWID) values(‘CHPEE‘)
insert into @T2 (FirstName,CWID) values(‘1111‘,‘aaa‘)
-- 当关联条件的字段为同一个名字时,这种写法不能重命名(变量表的话,也不能用表名)
--update @T2 set FirstName=b.firstname
--from @T1 b where b.ID=ID
select * From @T2
-- 下面这种写法解决了上面的问题
--没有匹配的不更新
update t2
set FirstName=t1.FirstName
from @T2 t2
inner join
@T1 t1 on t1.ID=t2.ID
--没有匹配的设为null
--update t2
--set FirstName=t1.FirstName
--from @T2 t2
--left join
--@T1 t1 on t1.ID=t2.ID
--
select *from @T2
set nocount off;
42,
sql查询数据时,选择的列很多时,如果join条件的列对应的自定义索引所对应的列不全在其中,可能会就会找主键。。。
with(nolock forceseek) 强制用Join列的主键。。。
with(nolock)
43, updatePanel和uploadFile控件不能共存,提交后,uploadFile里的值都是空的,所以遇到UpdatePanel不能去掉的情况:再弹个新窗口
------------------------------------------------------------------
44, 存储过程的参数是表类型,表级导入的速度是行集的N倍
-
CREATE Type [TBIZ_LUMP_CropPhoneSetting_InputTable] as Table
(
[CropPhoneUpdateLogID] [int] NULL,
[CompanyCode] [nvarchar](50) NOT NULL,
[CWID] [nvarchar](50) NULL,
[EmployeeID] [nvarchar](50) NULL,
[Name] [nvarchar](50) NULL,
[CostCenterCode] [nvarchar](50) NULL,
[DeliveryAddress] [nvarchar](500) NULL,
[PhoneNum] [nvarchar](50) NULL,
[iPhoneModel] [nvarchar](50) NULL,
[ServiceMonth] [int] NOT NULL,
[MacAddr] [nvarchar](50) NULL,
[SerialNo] [nvarchar](50) NULL,
[iPhoneNo] [nvarchar](50) NULL,
[AssetNo] [nvarchar](50) NULL,
[DeliveryDate] [nvarchar](50) NOT NULL,
[MDMName] [nvarchar](50) NULL,
[MDMPassword] [nvarchar](50) NULL,
[MDMAccountStatus] [nvarchar](50) NULL,
[CreatedBy] int NULL,
[CreateTime] datetime NULL,
[LastModifyBy] int NULL,
[LastModifyTime] datetime NULL
)
go
create proc BP_LUMP_UpdateCropPhoneSettingAndHistory @InputTable TBIZ_LUMP_CropPhoneSetting_InputTable readonly
as
begin
truncate table TBIZ_LUMP_CropPhoneSetting
insert into TBIZ_LUMP_CropPhoneSetting([CropPhoneUpdateLogID],[CompanyCode],[CWID],[EmployeeID],[Name],
[CostCenterCode],[DeliveryAddress],[PhoneNum],[iPhoneModel],[ServiceMonth],[MacAddr],[SerialNo],
[iPhoneNo],[AssetNo],
[DeliveryDate],
[MDMName],[MDMPassword],[MDMAccountStatus],
[CreatedBy],[CreateTime],
[LastModifyBy],[LastModifyTime]
)
select [CropPhoneUpdateLogID],[CompanyCode],[CWID],[EmployeeID],[Name],
[CostCenterCode],[DeliveryAddress],[PhoneNum],[iPhoneModel],[ServiceMonth],[MacAddr],[SerialNo],
[iPhoneNo],[AssetNo],
[DeliveryDate],
[MDMName],[MDMPassword],[MDMAccountStatus],
[CreatedBy],[CreateTime],
[LastModifyBy],[LastModifyTime]
from @InputTable
insert into TBIZ_LUMP_CropPhoneSetting_history([CropPhoneUpdateLogID],[CompanyCode],[CWID],[EmployeeID],[Name],
[CostCenterCode],[DeliveryAddress],[PhoneNum],[iPhoneModel],[ServiceMonth],[MacAddr],[SerialNo],
[iPhoneNo],[AssetNo],
[DeliveryDate],
[MDMName],[MDMPassword],[MDMAccountStatus],
[CreatedBy],[CreateTime],
[LastModifyBy],[LastModifyTime]
)
select [CropPhoneUpdateLogID],[CompanyCode],[CWID],[EmployeeID],[Name],
[CostCenterCode],[DeliveryAddress],[PhoneNum],[iPhoneModel],[ServiceMonth],[MacAddr],[SerialNo],
[iPhoneNo],[AssetNo],
[DeliveryDate],
[MDMName],[MDMPassword],[MDMAccountStatus],
[CreatedBy],[CreateTime],
[LastModifyBy],[LastModifyTime]
from @InputTable
end
--------------------------------------------------------------
45, check in 最好是一个功能
46, Kinect 、 AForge
47 ViewState写法套用
public string OrderField
{
get
{
if (ViewState["Order_Field"] == null)
{
ViewState["Order_Field"] = "Created Desc";
}
return ViewState["Order_Field"].ToString();
}
set
{
ViewState["Order_Field"] = value;
}
}
48, SQL 截断字符生成临时表
ALTER function [dbo].[func_SplitStr] (@str varchar(8000), @sperator varchar(1))
returns @tb table (Item varchar(500))
as
/******************************************************
* 名 称:[func_SplitStr]
*
* 功 能:用于截断字符生成临时表
*
* 作 者:RJ
*
*
******************************************************/
begin
declare @i int
declare @inext int
declare @temp varchar(500)
set @i=1
set @inext=1
while @inext>0
begin
set @inext=charindex(@sperator,@str,@i)
if @inext<=0
set @temp=substring(@str,@i,len(@str)-@i+1)
else
set @temp=substring(@str,@i,@inext-@i)
if len(@temp)>0
insert into @tb(Item) values (@temp)
set @i=@inext+1
end
return
end
GO
----------------
49
select * into NewT from OldT 建了一个同结构的表
50,
总去做页面,慢慢人就傻了吧,学编程时的一些常写的功能基本好多都是现在项目所谓的底层代码,但是貌似接触的越来越少了。
51, IE调Ajax请求
52, sp_who 可以查看数据库中正在连接的用户,Kill spid就可以断开此连接
53,使用Telerik控件时,可以在页面中使用RadAjaxManager控件指定页面中需要部分刷新的部分,也可以在后台中写要输出的脚本。但是一个页面中只允许出现一次,这种情况可以通过<telerik:RadAjaxManagerProxy runat="server" > 不需要设ID
54
<telerik:RadAjaxManager runat="server" ID="radAjax">
<AjaxSettings>
<telerik:AjaxSetting AjaxControlID="divPageAll">
<UpdatedControls>
<telerik:AjaxUpdatedControl ControlID="divPageAll" LoadingPanelID="RadAjaxLoadingPanel1"/>
</UpdatedControls>
</telerik:AjaxSetting>
</AjaxSettings>
</telerik:RadAjaxManager>
<telerik:RadAjaxLoadingPanel ID="RadAjaxLoadingPanel1" runat="server" Skin="Transparent"
EnableEmbeddedSkins="true">
</telerik:RadAjaxLoadingPanel>
注释:divPageAll中所有的事件,用RadAjaxLoadingPanel1遮住
53, OnInit时ViewState还木有加载
54 自定义验证控件
<asp:CustomValidator ID="CustomValidator3" runat="server" ErrorMessage="License Copy can‘t be empty"
Display="None" ControlToValidate="Basic_LicenseCopy" ClientValidationFunction="ValidateCopy"></asp:CustomValidator>
function ValidateCopy(sender, args) {
var copyCount = ‘<%=this.LicenseCopyCount %>‘;
if (copyCount == ‘0‘) {
args.IsValid = false; //设置这个属性, true通过,false不通过
}
}
55, 前端移除、添加服务端验证控件
Array.remove(Page_Validators, document.getElementById(‘<%=RequiredFieldValidator1.ClientID %>‘));
Array.add(Page_Validators, document.getElementById(‘<%=RequiredFieldValidator1.ClientID %>‘));
56, 存储过程中加上with recompile ,指示数据库引擎不缓存该过程的计划,该过程在运行时编译
57, id尽量是静态的。valuestate能禁用尽量禁用
ERS遇到的问题及solution