
圖:復(fù)雜報表外掛最終效果
此復(fù)雜報表外掛具有如下特點:
按前面“自定義報表/SQL命令行工具”介紹的方法,準(zhǔn)備查詢SQL語句,如下圖。

圖:使用SQL命令行工具準(zhǔn)備SQL查詢語句
按上一節(jié)介紹的方法建立項目W2,在W2上右鍵鼠標(biāo),在彈出菜單中選【添加】/【新建項】,如下圖。

圖:添加數(shù)據(jù)集(默認(rèn)名稱不要更改)
在打開的DataSet1.xsd面板中,右鍵鼠標(biāo),如下圖。

圖:添加TableAdapter
在彈出的“添加連接”窗口,錄入數(shù)據(jù)庫服務(wù)器相關(guān)信息,如下圖。

圖:連接數(shù)據(jù)庫
根據(jù)TableAdapter配置向?qū)нM行配置,如下圖。

圖:不要在連接字符串中包含敏感數(shù)據(jù)

圖:默認(rèn)下一步

圖:默認(rèn)下一步
粘貼準(zhǔn)備好的查詢SQL語句,點【完成】,如下圖。

圖:粘貼準(zhǔn)備好的查詢SQL語句
執(zhí)行查詢SQL語句所得的數(shù)據(jù)表字段,如下圖。

圖:查詢所得的數(shù)據(jù)表字段
在W2上右鍵鼠標(biāo),在彈出菜單中選【添加】/【新建項】,如下圖。

圖:添加報表文件(默認(rèn)名稱不要更改)
在打開的報表文件界面,右鍵“數(shù)據(jù)集”,選擇剛剛配置的數(shù)據(jù)集,如下圖。

圖:選擇數(shù)據(jù)集
在報表設(shè)計界面,右鍵鼠標(biāo),可以插入文本框等等,也可以把左側(cè)的數(shù)據(jù)集下面的字段拖放到報表設(shè)計界面,如下圖。

圖:報表設(shè)計
報表設(shè)計是最繁瑣最費時間的事情,最終設(shè)計結(jié)果,如下圖。

圖:報表設(shè)計結(jié)果
打開Form1窗體,從工具箱拖放一個ReportViewer報表查看器到窗體,如下圖。

圖:把報表查看器添加到窗體
雙擊Form1窗體,如圖30-26,清空窗體中所有的代碼,并把下面的代碼復(fù)制粘貼進去。

圖:Form1代碼窗口
using?Microsoft.Reporting.WinForms;
using?System;
using?System.Collections.Generic;
using?System.ComponentModel;
using?System.Data;
using?System.Data.SqlClient;
using?System.Drawing;
using?System.Linq;
using?System.Text;
using?System.Threading.Tasks;
using?System.Windows.Forms;
namespace?W2
{
public?partial?class?Form1?:?Form
{
public?string?_userID =?“”; ?????????????//登錄用戶ID
public?string?_serverIP =?@”.\_MSSQL2005″;?//服務(wù)器IP(如果是SQL企業(yè)版,則為“.”)
public?string?_dbName =?“bdERP”; ?????????????????????//數(shù)據(jù)庫名稱
public?string?_saPassword =?“17312319729@bijiade.cn”;?//sa密碼
public?string?_curDir =?@”..\..\”; ???????????????????//當(dāng)前目錄
public?Form1(){?InitializeComponent();?}
public?void?ShowMe(string?userID,?string?serverIP,?string?dbName,?string?saPassword,?string?curDir)//鉤子方法
{
_userID = userID; ??????????//傳遞用戶登錄ID
_serverIP = serverIP; ??????//服務(wù)器IP
_dbName = dbName; ??????????//數(shù)據(jù)庫名稱
_saPassword = saPassword; ??//sa密碼
_curDir = curDir; ??????????//當(dāng)前目錄
MessageBox.Show(“用戶ID:”?+ _userID +?“\n數(shù)據(jù)庫服務(wù)器IP:”?+ _serverIP +?“\n數(shù)據(jù)庫名稱:”?+ _dbName +?“\nsa密碼:”?+ _saPassword +?“\n當(dāng)前目錄:”?+ _curDir,?“提示”);
base.Show();//顯示窗體
}
private?void?Form1_Load(object?sender,?EventArgs?e)
{
//1.SQL查詢語句
string?sql =?@”
SELECT
a.c010 單號, a.c020 日期, a.c200 銷售類型, a.c210 客戶單號,
a.c030 客戶代碼, c.c020 客戶名稱,
a.c090 聯(lián)系人, a.c091 聯(lián)系電話,
a.c070 交貨方式, a.c080 交貨地點, ?a.c100 備注, a.c110 業(yè)務(wù)員,
b.c020 項次, b.c029 客戶料號, b.c030 貨品代碼,
b.c050 品名規(guī)格, b.c060 單位, b.c069 含稅, b.c070 單價, b.c071 含稅單價,
b.c080 數(shù)量, b.c090 金額, b.c100 稅率, b.c101 稅額, b.c110 價稅合計,
b.c150 摘要
FROM SAL020 a
LEFT JOIN SAL021 b ON b.c010=a.c010
LEFT JOIN BAS010 c ON c.c010=a.c030
WHERE 1=1 AND a.c061<>’Y’
AND a.c010=’XCK-21060001′
“;
//2.報表文件名(如果報表文件與外掛程序在同一目錄,直接寫報表名稱即可)
string?reportName = _curDir +?@”Report1.rdlc”;
//3.綁定
Bind(sql, reportName);
}
///?<summary>
///?工具方法,執(zhí)行SQL查詢獲取數(shù)據(jù),并綁定到指定報表。
///?</summary>
///?<param name=”sql”>SQL查詢語句</param>
///?<param name=”reportName”>報表文件名</param>
private?void?Bind(string?sql,?string?reportName)
{
DataTable?data =?new?DataTable(); ??????????????????????????//數(shù)據(jù)
try
{
//執(zhí)行SQL查詢獲取數(shù)據(jù)
string?connStr =?“Data Source=”?+ _serverIP +?@”;Initial Catalog=”?+ _dbName +?“;Persist Security Info=True;”?+
“User ID=sa;Password=”?+ _saPassword;
using?(SqlConnection?conn =?new?SqlConnection())
{
conn.ConnectionString = connStr;
conn.Open(); ?????????????????????//打開數(shù)據(jù)庫連接
SqlDataAdapter?adapt =?new?SqlDataAdapter(sql, conn);//實例化適配器
adapt.Fill(data); ???????????????????????????????????//獲取數(shù)據(jù)
conn.Close(); ??????????????????????????????????????//關(guān)閉數(shù)據(jù)庫連接
}
//綁定到指定報表
ReportDataSource?rds =?new?ReportDataSource();
rds.Name =?“DataSet1”; ?????????????????//要與數(shù)據(jù)集屬性數(shù)據(jù)集名稱要一致
rds.Value = data;
this.reportViewer1.LocalReport.DataSources.Clear();
this.reportViewer1.LocalReport.DataSources.Add(rds);
this.reportViewer1.LocalReport.ReportPath = reportName; ?//報表文件名
this.reportViewer1.RefreshReport();
}
catch?(Exception?ex) {?MessageBox.Show(“出錯了:\n”?+ ex.Message,?“提示”,?MessageBoxButtons.OK,?MessageBoxIcon.Error); }
}
}
}
以上代碼已經(jīng)在注釋中進行了講解,看不懂也沒有關(guān)系,只要依葫蘆畫瓢,要改2個地方(上面代碼已說明):其一是SQL查詢語句;其二是報表文件名稱(注意路徑)。如下圖。

圖:代碼關(guān)鍵點(SQL查詢語句、報表文件名)
鼠標(biāo)右鍵W2,在彈出菜單中選【屬性】,目標(biāo)框架選.NET 3.5,如下圖。

圖:選.NET Framework 3.5
提醒:這里輸出類型保持默認(rèn),為了便于測試。測試正常后,可以改為“類庫”。
拷貝外掛程序到ERP的外掛目錄下,并確認(rèn)運行正常,如下圖。

圖:拷貝外掛程序到ERP的外掛目錄下
打開【系統(tǒng)設(shè)置】/【外掛程序接口】,選擇子系統(tǒng),配置外掛程序接口參數(shù),測試是否可以正常打開外掛程序,最后點【保存并應(yīng)用】,如下圖。

圖:外掛程序接口
①報表外掛的意義。幣加德ERP系統(tǒng)的單據(jù)打印都是基于Excel的(參見“第23章 單據(jù)打印格式設(shè)計”),一般情況下無需開發(fā).rdlc報表,除非現(xiàn)有報表滿足不了業(yè)務(wù)需求。這里以開發(fā).rdlc報表為例,不僅僅為了說明報表開發(fā)本身,而且可以學(xué)習(xí)到如何集成ERP中的用戶ID、賬套數(shù)據(jù)庫等,無需另外配置數(shù)據(jù)庫連接和建立賬戶體系。
②幣加德ERP外掛接口規(guī)范。會傳遞如下這些參數(shù)給外掛程序,外掛程序可以不使用,或者部分使用,但是不能缺少這些參數(shù),順序也不能改變。
///?<summary>
///?鉤子方法。
///?</summary>
///?<param name=”userID”>用戶登錄ID</param>
///?<param name=”serverIP”>服務(wù)器IP</param>
///?<param name=”dbName”>數(shù)據(jù)庫名稱</param>
///?<param name=”saPassword”>sa密碼</param>
///?<param name=”curDir”>當(dāng)前目錄</param>
public?void?ShowMe(string?userID,?string?serverIP,?string?dbName,?string?saPassword,?string?curDir)//鉤子方法
{
_userID = userID; ??????????//傳遞用戶登錄ID
label1.Text =?“登錄用戶ID:”?+ _userID;//標(biāo)簽顯示
base.Show();//顯示窗體
}
③使用Visual Studio 2013開發(fā).rdlc報表的關(guān)鍵是準(zhǔn)備SQL查詢語句、報表設(shè)計(最費時間)。報表設(shè)計有如下特點(注意點),如下圖。
1)拖放設(shè)計。數(shù)據(jù)字段按照SQL查詢語句的順序列示,直接拖放進行報表設(shè)計,簡單直觀。
2)設(shè)計時可以調(diào)整紙張大小。報表默認(rèn)大小是A4縱向(可以更改),寬度不能超過“紙張寬度+邊距”,否則打印預(yù)覽時多出了很多空白頁(如果拉窄了寬度后,打印預(yù)覽時還是有空白頁,則需要把“報表”的“ConsumeContainerWhitesapce”屬性值改為True,此屬性意思“指使在容器中的內(nèi)容增長時,是占用還是保留容器中的最小空白。只要內(nèi)容右側(cè)和下方的空白受到影響。”)。縱向不用留空間,在打印時根據(jù)數(shù)據(jù)行數(shù)自動拉高。
3)數(shù)據(jù)表是一個整體。當(dāng)在設(shè)計時插入表格,表格是一個整體,但是列頭在多頁時重復(fù)顯示功能時不時卡殼(tablix“Tablix2”具有無效的?TablixMember。TablixColumnHierarchy?中所有?TablixMember?元素的?RepeatOnNewPage?屬性必須設(shè)置為?false。),所以建議把標(biāo)題欄刪除,手工增加文本框代替,放在頁眉處,這樣每頁都會顯示。
4)數(shù)據(jù)區(qū)可多級分組。報表的核心在于數(shù)據(jù)區(qū),可以分組匯總等。
5)頁眉/頁腳。頁腳可以插入頁碼,加上印章(透明處理參見第23章)等。
提醒:如果報表外掛程序在集成到ERP前運行得好好的,集成后出錯,最大的可能性有2種:其一如果提示“此程序集的運行時比當(dāng)前加載的運行時新,無法加載此程序集”,則是因為選錯了.NET版本(參見“圖30-28?選.NET Framework 3.5”);其二如果報表無法顯示,則是因為報表路徑錯了,或者報表文件Report1.rdlc沒有和外掛程序一起復(fù)制到ERP的外掛程序目錄中。

圖:報表設(shè)計特點(注意點)

圖:把“報表”的“ConsumeContainerWhitesapce”屬性值改為True
]]>
外掛程序作用:擴充ERP功能。滿足企業(yè)的行業(yè)化、個性化需求。
外掛程序接口特點:
ERP根目錄\外掛程序\W1\
外掛程序集成在幣加德ERP的菜單欄中,如下圖。

圖:外掛程序接口及系統(tǒng)集成位置
本節(jié)使用Visual Studio 2013(速成版、社區(qū)版、專業(yè)版、高級版、旗艦版都可以,前面2個版本是免費的)來開發(fā)外掛程序,如果你使用的是其他版本的Visual Studio,也可以參照學(xué)習(xí),大同小異。本節(jié)先用完整詳細(xì)的步驟介紹一個最簡單的外掛程序的開發(fā),通過此外掛的學(xué)習(xí),可以完全掌握外掛的開發(fā)方法。然后用較簡潔的步驟介紹如何開發(fā)報表外掛,這個案例很實用,企業(yè)的程序開發(fā)人員或ERP代理服務(wù)商經(jīng)常需要從企業(yè)ERP中取數(shù),開發(fā)分析報表或開發(fā)定制格式的打印單據(jù)。
①打開Visual Studio 2013,點【文件】/【新建】/【項目】,如下圖。

圖:新建項目
②在“新建項目”窗口,選擇【Visual C#】/【W(wǎng)indows 窗體應(yīng)用程序】,名稱為“W1”,如下圖。

圖:選擇Windows 窗體應(yīng)用程序
③從“工具箱”中拖一個Label到窗體設(shè)計界面,如下圖。

圖:拖一個標(biāo)簽到設(shè)計面板
④雙擊設(shè)計面板,打開代碼編輯窗口,輸入以下代碼,如下圖。
public?string?_userID =?“”; ????//登錄用戶ID
public?void?ShowMe(string?userID,?string?serverIP,?string?dbName,?string?saPassword,?string?curDir)//鉤子方法
{
_userID = userID; ??????????//傳遞用戶登錄ID
label1.Text =?“登錄用戶ID:”?+ _userID;//標(biāo)簽顯示
base.Show();//顯示窗體
}

圖:寫程序代碼
提醒:不管寫什么類型的外掛程序,都需要上面的代碼,相當(dāng)于ERP與外掛程序之間約定的一種協(xié)議,目的在于把ERP系統(tǒng)當(dāng)前的登錄用戶ID傳遞給外掛程序,并打開外掛程序的主窗體。除此之外,外掛程序與普通的Windows窗體程序沒有任何區(qū)別。
外掛程序可以查詢ERP的后臺數(shù)據(jù)表,但千萬別修改(刪除)數(shù)據(jù),這是一個基本的原則。否則出錯后無法核查是ERP的問題,還是外掛程序的問題。
⑤鼠標(biāo)右鍵項目名稱,在上下文菜單中選【屬性】,在打開的窗口中,“目標(biāo)框架”選擇“.NET Framework 2.0”(為了兼容老電腦),“輸出類型”選“類庫”(如果選“Windows應(yīng)用程序”,用戶可以越過權(quán)限設(shè)置,直接運行外掛程序),如下圖。

圖:設(shè)置項目屬性
⑥再次點【啟動】,系統(tǒng)會報錯(因上一步中改變了目標(biāo)框架),修正錯誤,如下圖。

圖:修改錯誤
⑦再次點【啟動】,系統(tǒng)會彈出無法直接啟動類庫項目的錯誤,這正是所要的,如下圖。

圖:彈出無法直接啟動類庫項目的錯誤
⑧打開外掛程序的輸出目錄(參見“圖30-3 選擇Windows 窗體應(yīng)用程序”選定的位置),并把外掛程序復(fù)制到ERP的外掛程序目錄,如下圖。


圖:拷貝外掛程序至ERP外掛目錄
①打開【系統(tǒng)設(shè)置】/【外掛程序接口】,選擇子系統(tǒng),配置外掛程序接口參數(shù),測試是否可以正常打開外掛程序,最后點【保存并應(yīng)用】,如下圖。
外掛程序接口參數(shù):

圖:外掛程序接口
提醒:外掛程序?+ ERP數(shù)據(jù)字典?=?無限擴展?ERP?功能!
(無需“幣加德ERP系統(tǒng)”源代碼)
]]>
圖:SQL命令行工具

圖:根據(jù)模板生成SQL語句

圖:拖拽表名稱節(jié)點生成SQL語句片段
提醒:SQL命令行工具會直接操作后臺數(shù)據(jù)庫表,如果誤操作會導(dǎo)致數(shù)據(jù)丟失,最好先在測試賬套測試好之后再應(yīng)用到正式賬套上,以免誤操作損壞實際業(yè)務(wù)數(shù)據(jù)。
數(shù)據(jù)庫主要包括增、刪、改、查等基本操作,以下為設(shè)計到的常用的sql語句:
一、查
1.select 語法查詢
SELECT?column_name,column_name?FROM?table_name
其中column_name為數(shù)據(jù)庫表列名字段,table_name為表名稱
如:select * from people 表示查詢people表內(nèi)所有列,返回所有記錄,*表示所有列
如:select? name,age from people 表示查詢people表內(nèi)名稱為name和age的列
2.select distinct 語法,查詢非重復(fù)項
SELECT DISTINCT?column_name,column_name?FROM?table_name
添加?DISTINCT 關(guān)鍵字會對查詢結(jié)果進行去重,返回唯一的值,注意:查詢多個列時,只有多個列的值全都相同,才認(rèn)為是相同的結(jié)果,否則不會去重
3.where 語法
SELECT column_name,column_name FROM table_name WHERE column_name operator value
如:select * from people where name=’小明’ 表示查詢people表內(nèi),名為“小明”的記錄
4.and 和 or 運算符
and 和 or 運算符連接多個查詢條件,配合where語法使用
如:select * from people where age>20 and country=’CN’ 表示查詢ipeople 表內(nèi)age字段值大于20并且country 字段為“CN”的記錄
二、增
1.insert into 語句
INSERT INTO table_name VALUES (value1,value2,value3,…),此語法需要把所有列的值寫全,否則不成功
INSERT INTO table_name (column1,column2,column3,…) VALUES (value1,value2,value3,…)
如:insert into people (name,age) values (‘張三’,30),表示向people表內(nèi)插入一條記錄,name為“張三”,age為30
三、改
1.update 語句
UPDATE table_name SET column1=value1,column2=value2, … WHERE some_column=some_value
如:update people set name=’李四’,age=’31’ where name=’張三’,表示將people表內(nèi)name等于“張三”的記錄,name改為“李四”,age改為31
四、刪
1.delete 語句
DELETE FROM table_name WHERE some_column=some_value
如:delete from people where name=’張三’,表示刪除people表內(nèi)name為“張三”的記錄
以上為最簡單的sql語法!
]]>