先看效果:
公司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 -->
至此,相關功能模塊主要代碼設計完畢。
預覽如下: