先看效果:
公司MIS 管理信息系统自2005 年建成投用以来,逐步实现了无纸化办公,提高了生产效率与管理水平。而我公司各种经济技术指标数据主要来源于三大块:
一、生产现场实时数据由DCS( 分布式控制系统Distributed Control System)->SIS( 厂级监控信息系统Supervisory lnformation System of Plant)->MIS 系统;
二、其它化验等非实时数据由责任人按规定录入MIS 系统;
三、其它第三方数据通过特定的接口进入MIS 系统;
MIS 系统根据工作需要进行综合计算,生成各种日报数据及相关报表,供决策者或技术人员分析使用。具体流程结构示意图如下:
图一:
由于MIS 系统中现有的各种经济技术指标日报由清一色报表表格组成,虽然很方便,但是无法对各种指标数据进行历史趋势分析,在一定程度上给管理及技术人员带来了不便,其在技术分析及辅助决策上瓶颈作用日益凸显。随着信息技术的发展与公司管理要求的不断细化,经过分析与学习,我利用一种友好可行的开发方案(c#.net+ amcharts+ajax )进行设计,实现经济技术指标日报的历史趋势曲线分析功能,完成公司MIS 经济技术指标数据由抽象报表向直观趋势分析的转变,给管理决策及技术分析提供有力辅助。
2. 数据结构及设计可行性分析
由于我公司MIS 系统采用c#.net+oracle 数据库开发,而amcharts 为一套专业flash 曲线图表组件,支持.net 及各种开发工具,可以生成各种具状图、曲线图、股票图、饼状图等等,其功能强大,界面美观,操作简单,因此我决定利用c#.net+ amcharts 开发设计来实现公司各种日报的历史趋势分析。
2.1 amcharts 应用分析
根据官方技术文档及实例,amcharts 要一个“ 配置文件” (setting.xml ),一个数据文件,一个 SWFObject.js ,一个对应的 SWF 就可以生成漂亮的统计报表了。配置文件,SWFObject.js ,对应的 SWF 系统自动提供,只需根据需要进行相应修改,而数据文件Amcharts 可以从简单的CSV 或XML 文件提取数据,也可以从动态数据读取生成, 比如PHP, .NET, Ruby on Rails 和Perl ,以及其他许多编程语言, 但必须遵循特定的数据样式。具体格式如下:
代码一:
<!-- amline script-->
<script type="text/javascript" src="amline/swfobject.js"></script>
<div id="flashcontent">
<strong>You need to upgrade your Flash Player</strong>
</div>
<script type="text/javascript">
// <![CDATA[
var so = new SWFObject("amline/amline.swf", "amline", "520", "400", "8", "#FFFFFF");
so.addVariable("path", "amline/");
so.addVariable("settings_file", encodeURIComponent("amline/amline_settings.xml"));
so.addVariable("data_file", encodeURIComponent("amline/amline_data.xml"));
so.write("flashcontent");
// ]]>
</script>
<!-- end of amline script -->
根据官方技术文档,可以同时定义多个配置文件,同时数据文件可以从动态数据中生成,因此核心语句可以变换如下:
so.addVariable("settings_file", encodeURIComponent("amline/amline_settings.xml, amline/amline_data.php?chart_id=1&city_id=2");
另外数据文件可以合并在配置文件里面,格式如下:
代码二:
<settings>
<!-- all the settings go here -->
<data>
<chart>
<series>
<value xid="100">1950</value>
.............................
</series>
.........
</chart>
</data>
</settings>
因此生成amcharts 曲线的基本要素可以确定,只需将动态数据文件及动态配置文件按“代码二“要求生成,即可满足要求。
2.2 公司经济技术指标日报数据格式分析
公司日报数据重点涉及到两张表:sts_dtarget t1,sts_dayvalues t2 。t1 为基础表,t2 为具体日报数据表表。结构如下:
图二:
根据数据结构,生成特定时间段、特定指标的日报数据的oracle 查询语句如下:
代码三 by wyw308 / http://blog.csdn.net/wyw308 :
Select t1.NAME 指标名称,t1.UNIT 单位,t1.CODE 指标代码, round(t2.NOW_VALUE,3) 日值, to_char(t2.INCEPT_DATE,'mm-dd') 接收日期
From sts_dtarget t1,sts_dayvalues t2
Where to_char(t2.INCEPT_DATE,'yyyymmdd')>='20110201' And to_char(t2.INCEPT_DATE,'yyyymmdd')<='20110216'
And t2.CODE in ('E01000101','E01000102') And t1.code=t2.code
order by t2.code,t2.INCEPT_DATE
此语句返回如下结构数据:
图三 by wyw308 / http://blog.csdn.net/wyw308 :
因此只需将查询到的类似“图三”语句按照要求生成“代码二”格式内容即可为flash 曲线组件所用。
2 .3 版面设计
核心功能实现了,现在只需根据功能需要设计相关交互界面。用c#.net 设计交互版面如下:
图四:by wyw308 / http://blog.csdn.net/wyw308
注:版面上相关”dtp_s” 类文字为相关控件的id 。
3. 详细代码设计
3.1 生成动态数据及配置文件的代码设计
设计sts_am.aspx 文件,传递参数格式如sts_am.aspx?s=2011-2-1&e=2011-2-16&c=B01001601;B01001600 ,此文件根据“图三 “数据,结合“代码二“格式,直接动态返回如下xml 内容,为图表组件所用:
图五:by wyw308 / http://blog.csdn.net/wyw308
实现此功能的核心代码:
代码四by wyw308 / http://blog.csdn.net/wyw308
private void Page_Load(object sender, System.EventArgs e)
{//页面载入时初始化by wyw308 / http://blog.csdn.net/wyw308
string code=Request.QueryString["c"];
string dt_s=Request.QueryString["s"];
string dt_e=Request.QueryString["e"];
if (dt_s==null||dt_s=="")
dt_s=System.DateTime.Today.AddDays(-31).ToString("yyyy-MM-dd");
if (dt_e==null||dt_e=="")
dt_e=System.DateTime.Today.AddDays(-1).ToString("yyyy-MM-dd");
Creat_Xml(dt_s,dt_e,code);
}
/// 配置文件和数据合在一起// 配置文件和数据合在一起
protected void Creat_Xml(string dt_s,string dt_e,string code)
{
int CodeNum,Tianshu,AllNum;
string Xml="";
string Xml_t="";
string Xml_m="";
CodeNum=0;
Tianshu=0;
AllNum=0;
int id=0;
DataSet ds=Am_xml(dt_s,dt_e,code);
string[] sArray=code.Split(new char[]{';'});
CodeNum=sArray.Length;
DateTime d1=System.DateTime.Today.AddDays(-1);
DateTime d2=DateTime.Parse(DateTime.Parse(dt_s).ToString("yyyy-MM-dd"));
DateTime d3=DateTime.Parse(DateTime.Parse(dt_e).ToString("yyyy-MM-dd"));
if(d1<d3)
d3=d1;
TimeSpan ts=d3-d2;
Tianshu=ts.Days+1;
AllNum=ds.Tables[0].Rows.Count;
if(CodeNum*Tianshu==AllNum)
{
Xml="<?xml version=/"1.0/" encoding=/"utf-8/"?>/n";
Xml+="<settings> /n";
Xml+="<graphs> /n ";
Xml_m="<data>";
Xml_m+="<chart> /n";
id=0;
for(int i=0;i<CodeNum;i++)
{
id=i+1;
Xml+="<graph gid=/""+id+"/"> /n ";
Xml+=" <axis>left</axis> /n";
Xml+="<title>"+ds.Tables[0].Rows[i*Tianshu][0].ToString()+"["+ds.Tables[0].Rows[i*Tianshu][1].ToString()+"]</title> /n";
Xml+="<selected>false</selected> /n";
Xml+="<balloon_text>/n";
Xml+=" <![CDATA[{value}]]>/n";
Xml+=" </balloon_text>/n";
Xml+=" </graph>/n";
if(i==0)
{
Xml_m+="<series>/n";
Xml_t="<graphs>/n";
Xml_t="<graph gid=/""+id+"/">/n";
for(int j=0;j<Tianshu;j++)
{
Xml_m+="<value xid=/""+j+"/">"+ds.Tables[0].Rows[j][4].ToString()+"</value>/n";
Xml_t+="<value xid=/""+j+"/">"+ds.Tables[0].Rows[j][3].ToString()+"</value>/n";
}
Xml_m+="</series>/n<graphs>";
Xml_t+="</graph>";
Xml_m=Xml_m+"/n"+Xml_t+"/n";
}
else
{
Xml_m+="<graph gid=/""+id+"/">/n";
for(int m=0;m<Tianshu;m++)
{
Xml_m+="<value xid=/""+m+"/">"+ds.Tables[0].Rows[i*Tianshu+m][3].ToString()+"</value>/n";
}
Xml_m+="</graph>/n";
}
}
Xml+=" </graphs> /n";
Xml_m+="</graphs>/n";
Xml_m+="</chart>/n";
Xml_m+= "</data>/n ";
Xml_m+="</settings>/n";
}
Xml=Xml+Xml_m;
Response.Clear();
Response.ContentType = "text/xml";
Response.Write(Xml);
Response.End();
}
private DataSet Am_xml(string dt_s,string dt_e,string code)
{
//by wyw308 / http://blog.csdn.net/wyw308
dt_s=(DateTime.Parse(dt_s)).ToString("yyyy-MM-dd").Replace("-","");
dt_e=(DateTime.Parse(dt_e)).ToString("yyyy-MM-dd").Replace("-","");
string sk;
sk="";
string[] sArray=code.Split(new char[]{';'});
for(int j=0;j<sArray.Length;j++)
{
if(j==0)
sk="'"+sArray[j].ToUpper()+"'";
else
sk=sk+",'"+sArray[j].ToUpper()+"'";
}
string sql="Select "+
" t1.NAME 指标名称,t1.UNIT 单位,t1.CODE 指标代码,"+
" round(t2.NOW_VALUE,3) 日值,"+
" to_char(t2.INCEPT_DATE,'mm-dd') 接收日期"+
" From sts_dtarget t1,sts_dayvalues t2"+
" Where to_char(t2.INCEPT_DATE,'yyyymmdd')>='"+dt_s+"' And to_char(t2.INCEPT_DATE,'yyyymmdd')<='"+dt_e+"'And t2.CODE in ("+sk+") And t1.code=t2.code order by t2.code,t2.INCEPT_DATE";
MyOraComm.ConnForOracle cfo=new MyOraComm.ConnForOracle("dbf_connstr");
DataSet ds=cfo.ReturnDataSet(sql,"ser");
cfo.CloseConn();
return ds;
}
3.2 页面模块功能代码设计
交互主页面文件:sts_day_am.aspx ;Javascript 功能文件:function.js ;有辅助线的静态配置文件:amline_settings_1.xml ;无辅助线的静态配置文件:amline_settings.xml 。
sts_day_am.aspx<head></head> 之间引用格式文件及javascript 功能文件如下:
<LINK href="amline/style.css" type="text/css" rel="stylesheet">
<script src="amline/function.js" language="javascript"></script>
sts_day_am.aspx 初始化时根据传递的参数或查询到的数据直接显示在各功能模块上主要代码:
private void Page_Load(object sender, System.EventArgs e)
{
AjaxPro.Utility.RegisterTypeForAjax(typeof(sts_day_am));
// 在此处放置用户代码以初始化页面
if(!Page.IsPostBack)
{
string code=Request.QueryString["c"];
dtp_s.Value=System.DateTime.Now.AddDays(-30);
dtp_e.Value=System.DateTime.Now.AddDays(-1);
bind_ddl_zhuanye_jizu();
bind_lst_code();
if(code!=""&&code!=null)
lst_bind_code(code);
lst_code.Attributes.Add("ondblclick","Move(/"lst_code/",/"lst_view/")");
lst_view.Attributes.Add("ondblclick","Move(/"lst_view/",/"lst_code/")");
}
}
private void bind_ddl_zhuanye_jizu()// 绑定专业和机组下拉列表
{
//by wyw308 / http://blog.csdn.net/wyw308
string sql="Select specialty_code,specialty_name from sts_each_specialty t Order By specialty_code";
string sql1="select machine_code,mahine_name from sts_each_machinery t Order By machine_code";
MyOraComm.ConnForOracle cfo=new MyOraComm.ConnForOracle("dbf_connstr");
ddl_zhuanye.DataSource=cfo.ReturnDataSet(sql,"zhuanye");
ddl_zhuanye.DataTextField="specialty_name";
ddl_zhuanye.DataValueField="specialty_code";
ddl_zhuanye.DataBind();
ddl_zhuanye.Items.Insert(0,new ListItem(" 全部专业","-1"));
ddl_jizu.DataSource=cfo.ReturnDataSet(sql1,"jizu");
ddl_jizu.DataTextField="mahine_name";
ddl_jizu.DataValueField="machine_code";
ddl_jizu.DataBind();
ddl_jizu.Items.Insert(0,new ListItem(" 全部","-1"));
cfo.CloseConn();
}
private void bind_lst_code() // 帮定数据到左listbox
{ lst_code.Items.Clear();
string sql="select code,Name||':'||unit Name,unit from sts_dtarget t where name like '%%'";
if(ddl_zhuanye.SelectedValue!="-1")
sql=sql+" and specialty_code='"+ddl_zhuanye.SelectedValue.ToString()+"'";
if(ddl_jizu.SelectedValue.ToString()!="-1")
sql=sql+" and machine_code='"+ddl_jizu.SelectedValue.ToString()+"'";
MyOraComm.ConnForOracle cfo=new MyOraComm.ConnForOracle("dbf_connstr");
DataSet ds=cfo.ReturnDataSet(sql,"sts_name");
lst_code.DataSource=ds;
lst_code.DataTextField="name";
lst_code.DataValueField="code";
lst_code.DataBind();
cfo.CloseConn();
}
private void lst_bind_code(string code) // 页面参数直接精确代码到列表 wyw308 by /20101229
{
string sk;
sk="";
lst_view.Items.Clear();
string[] sArray=code.Split(new char[]{';'});
for(int j=0;j<sArray.Length;j++)
{
if(j==0)
sk="'"+sArray[j].ToUpper()+"'";
else
sk=sk+",'"+sArray[j].ToUpper()+"'";
}
string sql="select code,Name||':'||unit Name,unit from sts_dtarget t where code in ( "+sk+")";
MyOraComm.ConnForOracle cfo=new MyOraComm.ConnForOracle("dbf_connstr");
DataSet ds=cfo.ReturnDataSet(sql,"sts_name");
lst_view.DataSource=ds;
lst_view.DataTextField="name";
lst_view.DataValueField="code";
lst_view.DataBind();
cfo.CloseConn();
}
“查询“按钮功能代码:
<input type="button" value=" 查询" onClick="javascript:yibu();">
Function.js 文件相关查询按钮所需代码
function yibu() // 异步方式处理
{
var ddl_zy=document.getElementById("ddl_zhuanye").value;
var ddl_jz=document.getElementById("ddl_jizu").value;
var txt_sc=document.getElementById("t_id").value;
var obj;
if(txt_sc!=null&&txt_sc!="")
{
arttj.sts_day_am.Get_List(ddl_zy,ddl_jz,txt_sc,yibu_callback); // 将Get_List 执行结果反馈给回调函数yibu_callback 的参数res, 然后回调函数接着处理此数据
}
else
{
alert(" 请输入查询数据!");
}
}
function yibu_callback(res) 异步方式处理,res 为Get_List 执行结果
{
//alert(res);
var ds=res.value;
var objsel = document.getElementById("lst_code");
if(ds != null && typeof(ds) == "object" && ds.Tables != null)
{
if(ds.Tables[0].Rows.length!=0)
{
for(var i = objsel.options.length - 1 ;i >= 0;i--)
{
objsel.options.remove(i)
}
for(var j=0; j<ds.Tables[0].Rows.length; j++)
{
var name=ds.Tables[0].Rows[j]["NAME"];
var id=ds.Tables[0].Rows[j]["CODE"];
// alert(name);
// alert(id);
objsel.options.add(new Option(name,id));
}
}
else
{
alert(" 没有查询到数据");
}
}
}
后台异步查询所需代码:
[AjaxPro.AjaxMethod]
public DataSet Get_List(string zy,string jz,string txt)
{
string sql="select code,Name||':'||unit Name,unit from sts_dtarget t where name like '%"+txt+"%'";
if(zy!="-1")
sql=sql+" and specialty_code='"+zy+"'";
if(jz!="-1")
sql=sql+" and machine_code='"+jz+"'";
MyOraComm.ConnForOracle cfo=new MyOraComm.ConnForOracle("dbf_connstr");
cfo.OpenConn();
DataSet ds=cfo.ReturnDataSet(sql,"sts_name");
cfo.CloseConn();
return ds;
}
“移动“,”删除“按钮代码
<INPUT type="button" value=" 移动" οnclick='javascript:Move("lst_code","lst_view");'>
<INPUT type="button" value=" 删除" οnclick='javascript:Move("lst_view","lst_code");'>
Function.js 相应功能代码:
function Move(from,to)
{
var objres = document.getElementById(from); // 源
var objsel = document.getElementById(to); // 目标
var customOptions;
for(var i = objres.options.length - 1 ;i >= 0;i--)
{
if(objres.options[i].selected)
{
customOptions = document.createElement("OPTION");
customOptions.text = objres.options[i].text;
//alert(customOptions.text);
customOptions.value = objres.options[i].value;
//alert(customOptions.value);
objsel.add(customOptions,0);
objres.remove(i);
}
}
refresh_am();
return false;
}
“显示“按钮代码:
<INPUT type="button" value=" 显示" onClick="javascript:refresh_am();">
Function.js 里相应代码:
function refresh_am()
{
var strlist = document.getElementById("lst_view");
var str= "";
if (strlist.options.length > 0) {
for (var i = 0; i < strlist.options.length; i++)
{
var j = strlist.options[i].value;
str+=j+";"; // 把Value 值串起来
}
var strValue=str.replace(/;$/, "");
//alert(strValue);
}
else {
alert("No Item in Listbox");
}
var Ckb_res=document.getElementById("fzx_id");
var s=rq(document.all("dtp_s_Value").value);
var e=rq(document.all("dtp_e_Value").value);
var strurl="c="+strValue+"&s="+s+"&e="+e;
// <![CDATA[
var so = new SWFObject("amline/amline.swf", "amline", "750", "480", "8", "#FFFFFF");
so.addVariable("path", "amline/");
if(Ckb_res.checked)
{
so.addVariable("settings_file", encodeURIComponent("amline/amline_settings_1.xml,sts_am.aspx?"+strurl));
}
else
{
so.addVariable("settings_file", encodeURIComponent("amline/amline_settings.xml,sts_am.aspx?"+strurl));
}
so.addVariable("loading_settings", " 加载配置...");
so.addVariable("loading_data", " 加载数据...");
so.addVariable("error_loading_file", "ERROR LOADING FILE");
so.write("flashcontent");
// ]]>
}
页面进入时直接显示相应曲线代码:
<!-- amline script-->
<script type="text/javascript" src="amline/swfobject.js"></script>
<div id="flashcontent">
<strong>You need to upgrade your Flash Player</strong>
</div>
<script type="text/javascript">
// <![CDATA[
refresh_am();
// ]]>
</script>
<!-- end of amline script -->
至此,相关功能模块主要代码设计完毕。
预览如下: