Visual Basic .Net (VB.Net) 程式語言案例學習 (04. 財產設備管理系統)
Visual Basic .Net (VB.Net) 程式語言案例學習 (04. 財產設備管理系統)¶
4.1 問題¶
這件案件源起於某學校總務處的提案,由於長時間使用紙本進行維修調閱,有時填表人填表錯誤,造成廢表,因而成為懸案,這種情形屢見不鮮,因為填表人可以是全校教職員及師生,約有三千五百多人,這套系統必須結合現有的學生資料庫,而學生由國中部到高中部約有三千多人,幼稚園加上教職員約有五百多人,每個人都必須有權利可以進行報修,只要發現有問題的設備或建築物,就要主動提報修單。之前的方式是以電話報修及紙本填表回報,常遇到問題,除了該處室的電話每天響個不停之外,有時候報修者未能提供必要資訊,這樣的流程造成處室十分捆擾,因此提案建立二十四小時且能包含全校教職員師生使用的報修系統。
因此最主要的問題,在於報修介面必須是步驟簡單且一致。
4.2 需求¶
表格 4‑1 「財產設備管理系統」系統需求表
| 版本:1.0 | 要做什麼 | 不要做什麼(不要做不代表不會做) |
|---|---|---|
| 能做什麼 | (第一格:必要項目) | (第二格:次要項目) |
| 全校師生、職員都必須能使用系統。 | 可以顯示特別訊息,凡是超過三天未完修的項目,就要顯示特別標示。 | |
| 報修介面儘量是一致。 | 製作日、週、月、年報表。 | |
| 系統要能包含所有建築物或是設備項目,以及可以新增項目。 | 可以依據班級列印賠償單據,以及賠償收據。 | |
| 報修單必須包含所有問題,以及可以新增問題。 | 報修者可以自行刪除報修單。 | |
| 系統管理者可以自由變更任何代碼,而變更後資料必須還要保持關連。 | 管理者可以刪除報修單。 | |
| 維修者可以回報維修情形。 | 管理者可將資料庫下載。 | |
| 非管理者無法使管理功能,維修者僅能回報維修情形,報修者只能填寫報修單。 | 一張報修單可對應多張報修單,讓多位維修人員一起來完成一張報修單。 | |
| 要清楚的讓使用者知道維修情形,顯示已完修及未完修的項目。 | 一張報修單可由管理者拆成多張工作單,讓維修人員選擇工作單工作。 | |
| 具有列印未完修以及已完修報表的功能。 | ||
| 填寫報修單的時候儘量與實際紙本欄位相同,並且使用點選的方式,但要保留可以新增資料的彈性。 | ||
| 增設其它外部連線的介面,讓其它經過驗證後的網站連結可以連入本系統。 | ||
| 維修者可以重複更新維修情形。 | ||
| 管理者可以在線上完成管理工作。 | ||
| 不能做什麼(不能做代表不需要做) | (第三格:不必要項目) | (第四格:不需要項目) |
| 提供地圖點選的方式,標示出地點供使用者報修時使用。 | 可以使用拖曳的方式,進行報修的動作。 | |
| 管理者功能中,提供報表產生的功能,提供群組報表。依據班級、建築物、處室。 | 管理者可以拒絕報修者的報修單。 | |
| 系統可以自行備份資料庫,以及維修、壓縮資料庫。 | ||
| 系統可以自行決定甚麼是比較重要的工作,提供給維修者參考。 |
表格 4‑2 「財產設備管理系統」系統目標分析表
| 版本: | 重要 | 不重要 |
|---|---|---|
| 優先 | (重) | (急) |
| 全校師生、職員都必須能使用系統。 | 維修者可以重複更新維修情形。 | |
| 報修介面儘量是一致。 | 具有列印未完修以及已完修報表的功能。 | |
| 系統要能包含所有建築物或是設備項目,以及可以新增項目。 | 要清楚的讓使用者知道維修情形,顯示已完修及未完修的項目。 | |
| 報修單必須包含所有問題,以及可以新增問題。 | ||
| 系統管理者可以自由變更任何代碼,而變更後資料必須還要保持關連。 | ||
| 維修者可以回報維修情形。 | ||
| 不急迫 | (輕) | (緩) |
| 填寫報修單的時候儘量與實際紙本欄位相同,並且使用點選的方式,但要保留可以新增資料的彈性。 | 管理者可以在線上完成管理工作。 | |
| 非管理者無法使管理功能,維修者僅能回報維修情形,報修者只能填寫報修單。 | 增設其它外部連線的介面,讓其它經過驗證後的網站連結可以連入本系統。 | |
| 管理者可以刪除報修單。 |
表格 4‑3 「財產設備管理系統」系統規格表
| 規格項目 | 規格內容 | 備註 |
|---|---|---|
| 首頁 | 顯示未完修及已完修的資料表。 | … |
| 提供可以列印未完修及已完修報表頁面。 | ||
| 登入區 | 提供全校教職員登入區、國中部、高中部登入區。 | … |
| 可以接收外部連結的呼叫介面。 | ||
| 報修單 | 報修單使用的欄位與紙本欄位相同,並增加可以新增內容的功能。 | … |
| 維修單 | 維修單可讓維修者查詢報修項目,並且一對一的回報維修情形。 | … |
| 維修單日期選擇採用日曆方式。 | ||
| 報修單項目可以進行排序。 | ||
| 建築物別除了使用者自訂以外,增設全校查詢的功能。 | ||
| 故障列表管理 | 管理者可以自由編碼,並且對編碼作新增、刪除、修改,而且不影響所有資料關聯。 | … |
| 故障列表可以進行排序,翻頁的功能。 | ||
| 處室編號管理 | 管理者可以自由新增、刪除、修改,而且不影響對所有資料的關聯。 | … |
| 處室列表可進行排序、翻頁。 | ||
| 人員權限管理 | 管理者可以自由新增、刪除、修改,而且不影響對所有資料的關聯。 | … |
| 可設定人員權限,得以隨時變動。 | ||
| 人員列表可進行排序、翻頁。 | ||
| 報修單管理 | 管理者可以刪除報修單。 | … |
| 報修單管理增設可以用關鍵字查詢。 | ||
| 報修單列表可以進行排序、翻頁。 | ||
| 單位管理 | 管理者可以自由新增、刪除、修改,而且不影響對所有資料的關聯。 | … |
| 單位管理表可以進行排序、翻頁。 | ||
| 單位管理表可以進行列印。 |
4.3 特色¶
非常特別的一點就是只用一張網頁,完成整套系統,並且供全校師生三千五百多人使用,毫無問題。
可應用於連鎖分店財產設備線上報修的系統。
甚至加以修改之後,還可以成為更完善的工作流(WorkFlow)系統。
4.4 使用工具¶
| 語言 | 軟體 |
|---|---|
| ASP.NET | MS Visual Studio 2005 .NET、MS Access、MS SQL Server |
4.5 系統架構¶
筆者一開始就在想,這套系統架構該是將其網頁分散開來設計,還是設計一頁網頁包含所有功能。當然傳統的做法是多頁的形式,透過許多的連結串成一套系統功能,但是現在ASP.NET卻可以設計成單網頁多功能。因此就系統面來看,使用者所提及的管理功能,多半是對資料庫作存取動作而已,而且介面上也可採用資料表的方式去設計,事實上整個系統的程式碼預估並不多,但需求者對於系統概念並不清楚,他所熟悉的是紙本的流程,而且紙本流程已經運行好一段時間了,因此筆者假設,紙本流程是符合使用者需求,因此才能運行這麼久。所以設計上以及與需求者觀念溝通上,皆採用紙本流程來進行,這樣至少有幾成的把握,接近使用者需求。在上述原因之下,筆者認為透過ASP.NET編譯出來的網頁會比較有效率,客戶端只需要讀取一張網頁就可以進行作業,面對各種不同背景的使用者,越簡單易懂的操作就是點選,而管理工作藉由資料表的方式,讓管理操作幾乎都一模一樣,人員權限上也十分簡單,因為並無牽涉到群組權限之類的問題,因此筆者自行分類為管理者角度、維修者角度、報修者角度,透過這三種角色來觀看系統,整個系統就會十分清楚明瞭。
4.6 程式實作¶
只需要一個步驟就可以完成了,將以下的程式碼插入-start-.aspx的<head>…</head>之中,並且注意所參考的命名,我們為了可以與SQL SERVER作連結,所以引用System.Data.SqlClient;要與本機資料庫作連結,因而引用System.Data.OleDb;而共用的參考是System.Data。
‘這為了要連結MS SQL Server所參考的命名
<%@ Import Namespace=”System.Data.SqlClient” %>
‘這為了要連結本機的MS ACCESS資料庫所參考的命名
<%@ Import Namespace=”System.Data.OleDb” %>
‘這為了要連結資料所參考的命名
<%@ Import Namespace=”System.Data” %>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
<html>
<head>
<title></title>
<script language=”vb” runat=”server”>
‘宣告陣列物件,方便由建築物下拉選單中選取項目
Dim ary_dll_PlaceBuild As New ArrayList()
‘宣告陣列物件,方便由教室下拉式選單中選取項目
Dim ary_dll_PlaceRoom As New ArrayList()
‘宣告陣列物件,方便由報修項目下拉式選單中選取項目
Dim ary_dll_Class As New ArrayList()
‘宣告陣列物件,方便由損壞情形下拉式選單中選取項目
Dim ary_dll_Item As New ArrayList()
‘宣告陣列物件,方便由故障分類下拉式選單中選取項目
Dim ary_dll_Bad As New ArrayList()
‘宣告陣列物件,方便由報修單位下拉式選單中選取項目
Dim ary_dll_Panel8_Classroom As New ArrayList()
‘宣告陣列物件,方便由教室下拉式選單中選取項目
Dim ary_dll_Unit As New ArrayList()
‘宣告陣列物件,方便由維修人員下拉式選單中選取項目
Dim ary_dll_WhoRepair As New ArrayList()
‘宣告陣列物件,方便由單位下拉式選單中選取項目
Dim ary_dll_ItemUnit As New ArrayList()
‘宣告陣列物件,方便由數量下拉式選單中選取項目
Dim ary_dll_Number As New ArrayList()
‘宣告陣列物件,方便由查詢欄位下拉式選單中選取項目
Dim ary_dll_Filter_DDL As New ArrayList()
‘使用者選擇是建築物或是教室的查詢開關
Dim bln_Buildname_or_Classroom As Boolean
‘宣告檢查變數,設是預留一個檢核的參數,讓外界的程式可以透過這三個參數登入
‘財產設備管理系統
Dim Non_Check_H, Non_Check_A, Non_Check_B
‘宣告建立資料表的函式
Function CreateDataSet(ByVal strSQL As String, ByVal FileName As String, ByVal TableName As String) As DataSet
‘宣告並設定連接資料庫字串變數
Dim ConnString As String = “Provider=Microsoft.Jet.OLEDB.4.0;” & _
“Data Source=” & Server.MapPath(FileName)
‘宣告並建立資料連接介面
Dim objCmd As New OleDbDataAdapter(strSQL, ConnString)
‘宣告並建立DataSet
Dim DS As New DataSet()
‘利用資立介面將資料表填滿DataSet
objCmd.Fill(DS, TableName)
‘傳回DataSet
CreateDataSet = DS
End Function
‘頁面初始化事件副程式
Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
‘接收部別字串
Non_Check_H = Trim(Request(“Non_Check_H”) & “”)
‘接收姓名字串
Non_Check_A = Trim(Request(“Non_Check_A”) & “”)
‘接收身分證字串
Non_Check_B = Trim(Request(“Non_Check_B”) & “”)
‘當姓名及身分證字串大於零時
If Len(Non_Check_A) > 0 And _
Len(Non_Check_B) > 0 Then
‘判斷部別字串,倘若為S則為高中部
If Non_Check_H = “S” Then
‘將姓名字串資料傳給姓名文字框
tbx_LN_student.Text = Non_Check_A
‘將身分證字串資料傳送給密碼文字框
tbx_PW_student.Text = Non_Check_B
‘顯示訊息
Response.Write(“ <font size=2 color=Red><b>請直接在高中部按下登入鈕。</b></font>”)
‘倘若為J則為國中部
ElseIf Non_Check_H = “J” Then
‘將姓名字串資料傳給姓名文字框
tbx_LN_student_jnr.Text = Non_Check_A
‘將身分證字串資料傳送給密碼文字框
tbx_PW_student_jnr.Text = Non_Check_B
‘顯示訊息
Response.Write(“ <font size=2 color=Red><b>請直接在國中部按下登入鈕。</b></font>”)
End If
End If
‘使用者選擇是建築物或是教室的查詢開關,設定為建築物
bln_Buildname_or_Classroom = True
‘宣告並建立資料庫連接物件
Dim objCnn As New OleDbConnection()
‘設定資料庫連結的連接字串
objCnn.ConnectionString = “provider=microsoft.jet.oledb.4.0;” & _
“data source=” & Server.MapPath(“./=DB=/errorReport.mdb”)
‘開啟資料庫
objCnn.Open()
‘宣告並建立命令物件
Dim objCmd As New OleDbCommand()
‘設定命令物件連結資料庫
objCmd.Connection = objCnn
‘宣告資料讀取物件
Dim objReader As OleDbDataReader
‘設定命令物件文字
objCmd.CommandText = “Select DISTINCT [buildname] From TPlace Order By [buildname]”
‘讀取命令物件傳回的結果
objReader = objCmd.ExecuteReader()
‘循序讀取資料物件
While objReader.Read()
‘讀取建築物資料並加入下拉式選單陣列
ary_dll_PlaceBuild.Add(objReader.GetValue(0))
End While
‘將下拉式選單資料綁定
dll_PlaceBuild.DataBind()
‘關閉讀取物件
objReader.Close()
‘手動加入全校的選項
ary_dll_PlaceBuild.Add(“全校”)
‘建築物別下拉式選單資料綁定
dll_Panel8_PlaceBuild.DataBind()
‘設定命令物件文字,找尋所有的物品類別
objCmd.CommandText = “Select DISTINCT [class] From Tproblem Order By [class]”
‘讀取所有物品類別
objReader = objCmd.ExecuteReader()
‘循序的讀取物品類別
While objReader.Read()
‘將物品類別加入至下拉式選單
ary_dll_Class.Add(objReader.GetValue(0))
End While
‘物品類別資料綁定
dll_Class.DataBind()
‘關閉讀取物件
objReader.Close()
‘設定命令物件文字,尋找破壞原因
objCmd.CommandText = “Select [badName] From Tbad Order By [autoID]”
‘讀取所有破壞原因
objReader = objCmd.ExecuteReader()
‘循序讀取破壞原因
While objReader.Read()
‘將破壞原因加入下拉式選單
ary_dll_Bad.Add(objReader.GetValue(0))
End While
‘破壞原因資料綁定
dll_Bad.DataBind()
‘關閉讀取物件
objReader.Close()
‘設定命令物件文字,尋找所有單位
objCmd.CommandText = “Select [unitSize] From Tsize Order By [unitSize]”
‘讀取單位資料
objReader = objCmd.ExecuteReader()
‘循序讀取單位資料
While objReader.Read()
‘將單位項目加入下拉式選單
ary_dll_ItemUnit.Add(objReader.GetValue(0))
End While
‘單位資料綁定
dll_Panel3_ItemUnit.DataBind()
‘關閉讀取物件
objReader.Close()
‘宣告計數器變數
Dim intI As Integer
‘由1到100迴圈
For intI = 1 To 100
‘加入數量下拉式選單
ary_dll_Number.Add(CStr(intI))
Next intI
‘將數量資料綁定
dll_Panel3_Number.DataBind()
‘關閉資料庫連線
objCnn.Close()
‘日期選擇起始日設定為今日
cld_Panel8_DateS.SelectedDate = DateTime.Today
‘日期選擇結束日設定為今日
cld_Panel8_DateE.SelectedDate = DateTime.Today
‘隱藏輸入發生地點文字框
tbx_PlaceRoom.Visible = False
‘顯示發生地點下拉式選單
dll_PlaceRoom.Visible = True
‘新增報修單管理項目
ary_dll_Filter_DDL.Add(“位置”)
ary_dll_Filter_DDL.Add(“報修日期”)
ary_dll_Filter_DDL.Add(“維修人員”)
ary_dll_Filter_DDL.Add(“項目”)
‘將項目資料綁定
Panel4_Filter_DDL.DataBind()
End Sub
‘頁面起始載入
Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
‘避免sLoadDB_dgd_Delete()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Delete()
‘避免sLoadDB_dgd_Panel_BFN()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel_BFN()
‘避免sLoadDB_dgd_Panel_BFY()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel_BFY()
‘避免sReload_dll_WhoRepair()資料重複載入
If Not IsPostBack Then sReload_dll_WhoRepair()
‘避免sReLoad_dll_Panel8_Classroom()資料重複載入
If Not IsPostBack Then sReLoad_dll_Panel8_Classroom()
‘避免sLoadDB_dgd_Panel5()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel5()
‘避免sLoadDB_dgd_Panel6()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel6()
‘避免sLoadDB_dgd_Panel7()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel7()
‘避免sLoadDB_dgd_Panel8()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel8()
‘避免sLoadDB_dgd_Panel10()資料重複載入
If Not IsPostBack Then sLoadDB_dgd_Panel10()
‘避免sInitload_dll_PlaceRoom()資料重複載入
If Not IsPostBack Then sInitload_dll_PlaceRoom()
‘避免sInitload_dll_Item()資料重複載入
If Not IsPostBack Then sInitload_dll_Item()
End Sub
‘宣告報修單管理載入資料副程式
Sub sLoadDB_dgd_Delete()
‘宣告SQL命令字串變數
Dim strSQL_Filter As String
‘將SQL字串清空
strSQL_Filter = “”
‘假若報修單管理的查詢文字大於零
If Len(Panel4_Filter_Text.Text) > 0 Then
‘則依據查詢欄位名稱,至作指定的SQL查詢文字
Select Case Panel4_Filter_DDL.SelectedItem.Text
‘查詢位置
Case “位置”
strSQL_Filter = “ AND [Tplace].[place] Like ‘%” & Trim(Panel4_Filter_Text.Text & “”) & “%’ “
‘查詢報修日期
Case “報修日期”
‘判斷輸入的文字是否為日期格式
If IsDate(Trim(Panel4_Filter_Text.Text & “”)) = True Then
strSQL_Filter = “ AND [dDate] Like #” & Trim(Panel4_Filter_Text.Text & “”) & “# “
‘不為日期格式
Else
‘顯示提示訊息
Panel4_Filter_Text.Text = “不正確的日期格式”
End If
‘查詢維修人員
Case “維修人員”
strSQL_Filter = “ AND [whoRepair] Like ‘%” & Trim(Panel4_Filter_Text.Text & “”) & “%’ “
‘查詢項目
Case “項目”
strSQL_Filter = “ AND [Tproblem.class] Like ‘%” & Trim(Panel4_Filter_Text.Text & “”) & “%’ “
End Select
End If
‘宣告SQL命令文字字串變數
Dim strSQL As String
‘設定SQL命令文字,主要在於關聯個資料表的資訊
strSQL = “SELECT [Task].[autoAskID],dDate,Cmemo,whoAsk,whyask,place,Tproblem.class,Tproblem.name,TPlace.buildname,cLooked,Classroom,loginUser,whoRepair,Trepair.solDate “ & _
“FROM Task,Tproblem,Tplace,Trepair “ & _
“WHERE Tproblem.pbID = Task.pbID AND “ & _
“Task.whereID = Tplace.whereID AND “ & _
“[Task].[autoAskID] = Trepair.autoAskID AND “ & _
“cLooked = ‘已完成’ AND “ & _
“delFlag = ‘0’ “
‘將主要查詢文字與報修管理查詢文字結合
strSQL = strSQL & strSQL_Filter
‘加入排序的SQL命令
strSQL = strSQL & “ ORDER BY [Task].[autoAskID] DESC “
‘執行SQL命令,並建立與資料庫的連結,傳回資料
Dim DS As DataSet = CreateDataSet(strSQL, _
“./=DB=/errorReport.mdb”, _
“Task,Tproblem,Tplace,Trepair”)
‘宣告並建立資料表檢視物件
Dim DV As New DataView(DS.Tables(“Task,Tproblem,Tplace,Trepair”))
‘將資料表的資料來源設定為資料表檢視物件
dgd_Delete.DataSource = DV
‘將資料表資料綁定
dgd_Delete.DataBind()
End Sub
‘登入確認副程式
Sub Login_Check(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs)
‘過濾帳號文字,取消單引號字元,避免SQL隱碼
tbx_LN.Text = Replace(tbx_LN.Text, “’”, “”)
‘過濾密碼文字,取消單引號字元,避免SQL隱碼
tbx_PW.Text = Replace(tbx_PW.Text, “’”, “”)
‘過濾帳號文字,取消百分比字元,避免SQL隱碼
tbx_LN.Text = Replace(tbx_LN.Text, “%”, “”)
‘過濾密碼文字,取消百分比字元,避免SQL隱碼
tbx_PW.Text = Replace(tbx_PW.Text, “%”, “”)
‘過濾帳號文字,取消星號字元,避免SQL隱碼
tbx_LN.Text = Replace(tbx_LN.Text, “*”, “”)
‘過濾密碼文字,取消星號字元,避免SQL隱碼
tbx_PW.Text = Replace(tbx_PW.Text, “*”, “”)
‘過濾高中部帳號文字,取消單引號字元,避免SQL隱碼
tbx_LN_student.Text = Replace(tbx_LN_student.Text, “’”, “”)
‘過濾高中部密碼文字,取消單引號字元,避免SQL隱碼
tbx_PW_student.Text = Replace(tbx_PW_student.Text, “’”, “”)
‘過濾高中部帳號文字,取消百分比字元,避免SQL隱碼
tbx_LN_student.Text = Replace(tbx_LN_student.Text, “%”, “”)
‘過濾高中部密碼文字,取消百分比字元,避免SQL隱碼
tbx_PW_student.Text = Replace(tbx_PW_student.Text, “%”, “”)
‘過濾高中部帳號文字,取消星號字元,避免SQL隱碼
tbx_LN_student.Text = Replace(tbx_LN_student.Text, “*”, “”)
‘過濾高中部密碼文字,取消星號字元,避免SQL隱碼
tbx_PW_student.Text = Replace(tbx_PW_student.Text, “*”, “”)
‘過濾國中部帳號文字,取消單引號字元,避免SQL隱碼
tbx_LN_student_jnr.Text = Replace(tbx_LN_student_jnr.Text, “’”, “”)
‘過濾國中部密碼文字,取消單引號字元,避免SQL隱碼
tbx_PW_student_jnr.Text = Replace(tbx_PW_student_jnr.Text, “’”, “”)
‘過濾國中部帳號文字,取消百分比字元,避免SQL隱碼
tbx_LN_student_jnr.Text = Replace(tbx_LN_student_jnr.Text, “%”, “”)
‘過濾國中部密碼文字,取消單引號字元,避免SQL隱碼
tbx_PW_student_jnr.Text = Replace(tbx_PW_student_jnr.Text, “%”, “”)
‘過濾國中部帳號文字,取消星號字元,避免SQL隱碼
tbx_LN_student_jnr.Text = Replace(tbx_LN_student_jnr.Text, “*”, “”)
‘過濾國中部密碼文字,取消星號字元,避免SQL隱碼
tbx_PW_student_jnr.Text = Replace(tbx_PW_student_jnr.Text, “*”, “”)
‘判斷登入按鈕名稱,若為教師登入
If e.CommandName = “Teacher” Then
‘宣告並建立資料庫連結物件
Dim objCnn As New OleDbConnection()
‘設定資料庫連結命令文字
objCnn.ConnectionString = “provider=microsoft.jet.oledb.4.0;” & _
“data source=” & Server.MapPath(“./=DB=/errorReport.mdb”)
‘開啟資料庫
objCnn.Open()
‘宣告並建立命令物件
Dim objCmd As New OleDbCommand()
‘設定命令物件與資料庫連結
objCmd.Connection = objCnn
‘設定命令文字
objCmd.CommandText = “Select [nameID],[name],[cPassword],[identification],[priv],[depart] “ & _
“From Tuser “ & _
“Where [nameID] Like ‘” & tbx_LN.Text & “’ And “ & _
“[cPassword] Like ‘” & tbx_PW.Text & “’”
‘宣告讀取物件並執行SQL命令傳回結果
Dim objReader As OleDbDataReader = objCmd.ExecuteReader()
‘假若有資料
If objReader.Read() = True Then
‘隱藏國中部登入PANEL
Panel_Student_jnr.Visible = False
‘隱藏教師登入PANEL
Panel_Teacher.Visible = False
‘隱藏高中部登入PANEL
Panel_Student.Visible = False
‘隱藏報修資訊看板PANEL
Panel_Board.Visible = False
‘顯示報修單PANEL
Panel3.Visible = True
‘判斷權限,若為管理者
If objReader.GetValue(4) = “SU” Then
‘顯示管理工具列
Panel1.Visible = True
‘若為維修人員
ElseIf objReader.GetValue(4) = “W” Then
‘隱藏管理工具列
Panel1.Visible = False
‘若為報修人員
Else
‘隱藏管理工具列
Panel1.Visible = False
‘隱藏建築物下拉式選單
dll_Panel8_PlaceBuild.Visible = False
‘隱藏地點下拉式選單
dll_Panel8_Classroom.Visible = False
‘隱藏標籤顯示
lab_Panel8_1.Visible = False
lab_Panel8_2.Visible = False
lab_Panel8_3.Visible = False
End If
‘顯示爆修工具列
Panel2.Visible = True
‘顯示姓名訊息
labLoginUser.Text = (objReader.GetValue(0) & “老師。”)
‘設定SESSION的帳號文字
Session(“LN”) = Trim(objReader.GetValue(0))
‘設定SESSION的密碼文字
Session(“PW”) = Trim(objReader.GetValue(2))
‘設定SESSION的姓名文字
Session(“name”) = Trim(objReader.GetValue(1))
‘設定SESSION的權限文字
Session(“priv”) = Trim(objReader.GetValue(4))
‘設定SESSION的部門文字
Session(“grade”) = Trim(objReader.GetValue(5))
‘設定報修者姓名文字
tbx_Panel3_whoAsk.Text = Trim(Session(“name”))
‘禁能報修者姓名文字框
tbx_Panel3_whoAsk.Enabled = False
‘設定報修處室名稱文字
tbx_Panel3_Unit.Text = Trim(Session(“grade”))
‘禁能報修處室名稱文字框
tbx_Panel3_Unit.Enabled = False
End If
‘倘若為高中部的學生
ElseIf e.CommandName = “Student” Then
‘宣告並建立SQL SERVER連結物件
Dim objCnn As New SqlConnection()
‘設定連結SQL SERVER命令文字
objCnn.ConnectionString = “workstation id=RD;” & _
“packet size=4096;” & _
“user id=你的帳號;” & _
“data source=你的SQL SERVER IP;” & _
“persist security info=True;” & _
“initial catalog=你的資料庫名稱;” & _
“password=你的密碼”
‘開啟資料庫
objCnn.Open()
‘宣告並建立SQL SERVER命令物件
Dim objCmd As New SqlCommand()
‘設定命令物件資料庫連結
objCmd.Connection = objCnn
‘當外來變數小於等於零時,代表由內部連結
If Len(Non_Check_B) <= 0 Then
‘設定命令文字
objCmd.CommandText = “Select [name],[student_number],[id],[grade] “ & _
“From student_accounting “ & _
“Where [student_number] Like ‘” & Left(tbx_LN_student.Text & “ “, 10) & “’ And “ & _
“[id] Like ‘” & Left(tbx_PW_student.Text & “ “, 30) & “’”
‘當外來變數大於零時,代表由外部連結
ElseIf Len(Non_Check_B) > 0 Then
‘設定命令文字
objCmd.CommandText = “Select [name],[student_number],[id],[grade] “ & _
“From student_accounting “ & _
“Where [student_number] Like ‘” & Left(tbx_LN_student.Text & “ “, 10) & “’ And “ & _
“[id] Like ‘” & Left(Non_Check_B & “ “, 30) & “’”
End If
‘宣告SQL SERVER讀取物件,並傳回結果
Dim objReader As SqlDataReader = objCmd.ExecuteReader()
‘假若有資料
If objReader.Read() = True Then
‘修改讓使用者清楚功能的名稱
btn_Panel2_04.Text = “報修登錄”
btn_Panel2_01.Text = “報修查詢”
‘顯示或隱藏高中部學生可用功能的PANEL
Panel_Board.Visible = False
Panel1.Visible = False
Panel2.Visible = True
Panel3.Visible = True
‘隱藏登入的PANEL
Panel_Student_jnr.Visible = False
Panel_Student.Visible = False
Panel_Teacher.Visible = False
‘隱藏非高中部學生可用的物件
dll_Panel8_PlaceBuild.Visible = False
dll_Panel8_Classroom.Visible = False
lab_Panel8_1.Visible = False
lab_Panel8_2.Visible = False
lab_Panel8_3.Visible = False
‘顯示登入姓名
labLoginUser.Text = (objReader.GetValue(0) & “同學。”)
‘設定SESSION的帳號文字
Session(“LN”) = Trim(objReader.GetValue(1))
‘設定SESSION的密碼文字
Session(“PW”) = Trim(objReader.GetValue(2))
‘設定SESSION的姓名文字
Session(“name”) = Trim(objReader.GetValue(0))
‘設定SESSION的權限文字
Session(“priv”) = “”
‘設定SESSION的部門文字
Session(“grade”) = Trim(objReader.GetValue(3))
‘設定報修者的姓名
tbx_Panel3_whoAsk.Text = Trim(Session(“name”))
‘禁能報修者的姓名文字框
tbx_Panel3_whoAsk.Enabled = False
‘設定報修者的部門
tbx_Panel3_Unit.Text = Trim(Session(“grade”))
‘禁能報修者的部門文字框
tbx_Panel3_Unit.Enabled = False
End If
‘假設是國中部的學生登入
ElseIf e.CommandName = “Student_jnr” Then
‘宣告並建立SQL SERVER連結物件
Dim objCnn As New SqlConnection()
‘設定SQL SERVER連結命令文字
objCnn.ConnectionString = “workstation id=RD;” & _
“packet size=4096;” & _
“user id=你的帳號;” & _
“data source=你SQL SERVER IP;” & _
“persist security info=True;” & _
“initial catalog=你的資料庫名稱;” & _
“password=你的密碼”
‘開啟資料庫
objCnn.Open()
‘宣告並建立SQL SERVER命令物件
Dim objCmd As New SqlCommand()
‘設定命令物件與SQL SERVER資料庫連結
objCmd.Connection = objCnn
‘假設不是外來變數
If Len(Non_Check_B) <= 0 Then
‘設定命令物件文字
objCmd.CommandText = “Select [name],[student_number],[id],[grade] “ & _
“From student_accounting “ & _
“Where [student_number] Like ‘” & Left(tbx_LN_student_jnr.Text & “ “, 10) & “’ And “ & _
“[id] Like ‘” & Left(tbx_PW_student_jnr.Text & “ “, 30) & “’”
‘假設是外來變數燈入
ElseIf Len(Non_Check_B) > 0 Then
‘設定命令文字
objCmd.CommandText = “Select [name],[student_number],[id],[grade] “ & _
“From student_accounting “ & _
“Where [student_number] Like ‘” & Left(tbx_LN_student_jnr.Text & “ “, 10) & “’ And “ & _
“[id] Like ‘” & Left(Non_Check_B & “ “, 30) & “’”
End If
‘宣告並執行SQL命令文字,傳回結果
Dim objReader As SqlDataReader = objCmd.ExecuteReader()
‘假設有資料
If objReader.Read() = True Then
‘更改顯示訊息讓國中部同學熟悉的名稱
btn_Panel2_04.Text = “報修登錄”
btn_Panel2_01.Text = “報修查詢”
‘顯示或隱藏國中部同學可用的PANEL
Panel_Board.Visible = False
Panel1.Visible = False
Panel2.Visible = True
Panel3.Visible = True
‘隱藏登入用的PANEL
Panel_Student_jnr.Visible = False
Panel_Student.Visible = False
Panel_Teacher.Visible = False
‘隱藏國中部同學不可見的物件
dll_Panel8_PlaceBuild.Visible = False
dll_Panel8_Classroom.Visible = False
lab_Panel8_1.Visible = False
lab_Panel8_2.Visible = False
lab_Panel8_3.Visible = False
‘顯示同學姓名
labLoginUser.Text = (objReader.GetValue(0) & “同學。”)
‘設定SESSION的帳號文字
Session(“LN”) = Trim(objReader.GetValue(1))
‘設定SESSION的密碼文字
Session(“PW”) = Trim(objReader.GetValue(2))
‘設定SESSION的姓名文字
Session(“name”) = Trim(objReader.GetValue(0))
‘設定SESSION的權限文字
Session(“priv”) = “”
‘設定SESSION的部門文字
Session(“grade”) = Trim(objReader.GetValue(3))
‘設定姓名文字
tbx_Panel3_whoAsk.Text = Trim(Session(“name”))
‘禁能姓名文字框
tbx_Panel3_whoAsk.Enabled = False
‘設定部門文字
tbx_Panel3_Unit.Text = Trim(Session(“grade”))
‘禁能部門文字框
tbx_Panel3_Unit.Enabled = False
End If
End If
End Sub
</script>
我們透過不同觀點來看完成的結果,首先是報修者角色,其次是維修者,最後是管理者。
首先是報修者,我們預設報修者帳號是tester,密碼是123。
圖 4‑1 報修者角色之報修單
圖 4‑2 報修者角色之維修回報
其次是維修者,我們預設維修者帳號是repair,密碼是123。
圖 4‑3 維修者角色之報修單
圖 4‑4 維修者角色之維修單
其次是管理者,我們預設管理者帳號是super,密碼是123。
圖 4‑5 管理者角色之報修單
圖 4‑6 管理者角色之維修單
圖 4‑7 管理者角色之故障列表管理
圖 4‑8 管理者角色之處室編號管理
圖 4‑9 管理者角色之人員權限管理
圖 4‑10 管理者角色之單位管理
4.7 修改重點¶
要結合現有人員資料庫系統,最好透過可連接ODBC的方式,如此就能與異質資料庫輕易的結合。而無須修改現有的資料庫系統,一般而言我們假設具有MS SQL Server資料庫,存放著既有的人員資料,修改只需修正連接的方式即可,因為本系統認證方式相當簡單,就是提取登入者的姓名及身分證字號,兩個欄位而已,只要滿足這兩個欄位就可以進行系統的操作。若要讓系統更加具有威力,可將整個系統搬到SQL SERVER上去運作,這樣效率也會比單機資料庫的要好得多。
要進入WorkFlow的流程,只需要加強設計表單的稽核、權限、工作流的部分,加以套用,讓管理者可以清楚的知道維修進度,維修者可以知道每日的工作,報修者可以收到維修的排程。其實這底層也只是資料的分析動作而已,並不會太難,您可以另闢網頁來撰寫,也可以直接在系統上修改。倘若您對於本系統運作相當有認同,不想修改,建議您採取外掛功能的方式,來進行工作流的增加,這樣在您修改的同時,也不會影響以上線的系統,因為您的目的只是擷取資料進行重新分析而以。反之,您認為系統有不足之處,想要進行系統的變更,建議您修改的同時,先將原始碼Mark起來,然後再進行修改,這樣如果使用者急需用到系統,您也只需要將原始碼還原即可。以上討論的是當系統上線時的修改方式。當然最後一種方式,就是另外創建系統檔案,以另外的網站來讀取相同資料庫的模式來修改,但這樣有時會造成資料庫相互鎖死的情形,必須要注意。
細心的讀者可以發現每一張資料表我們都採用自動編號來做為索引,而不使用所謂使用者定義的編號來做為索引,這是因為使用者需求自己要設定編號,因此我們必須確保在使用者修改編號之後,仍然能夠對應到相關連的資料,這點非常重要,若使用者要求能夠自由更改的權限,設計者就必須採取對應的措施,避免程式的錯誤。依據經驗,凡是使用者所要求的功能,資訊人員在設計的時候,千萬要避開,所為避開就是不要把使用者所要求開放的功能作為程式內部運作的重點,因為你無法要求使用者與你有相同的思維,特別面對沒有資訊背景的使用者,甚至無法解釋,特別是要開放給不同背景的全校師生所使用,而且開放出去的權限,想要收回是很難的。為了避開這種窘境,額外採取內部運作的編碼,是比較保險的做法。這也符合物件導向設計概念,有些資訊我們是要封裝起來,不需要讓使用者去設法改變,以確保系統穩定。
當然所有程式都有缺點,縱使這支程式已經運行多時,並且尚未出現問題,但平心而論,這支程式幾乎沒有做例外處理,這點並不是非常的好,希望讀者在修改的同時,請記得加入例外處理,這樣可以更確保程式的穩定性。
此外由於為了讓系統推廣順利,因此採用中文姓名當作帳號,讓使用者省去多帳號的捆擾,但卻因為少數人的中文姓名是必須額外編碼,對於這點我們必須採取另外的措施,協助使用者登入。
4.8 結論¶
在使用本系統之後,我們發現該處室的幾位維修人員功力不錯,曾有一連好幾個星期維修率是百分之百,這在尚未使用本系統前是很難統計出來的,而且對於維修人員來說,他們現在只需要定期上網瀏覽資訊,去維修後做回覆的動作,如此一來也不必直接面對客戶的抱怨,獲得的是客戶的稱讚。
在管理這套系統的組長方面,也因此能夠輕鬆的管理維修的進度,不必每天都要求維修人員回報,他也驚訝的發現這幾位維修人員的效率其實是很棒的,以前因為一些溝通不良的部分,都因為這套具有數據顯示的系統,反到證明了該組的工作效率。
系統因此進入了ISO流程,往後面對層出不窮的報修事件,藉由既定的流程作業,無論對於報修者及維修者皆是雙贏的局面。
在系統方面,這系統的主程式只使用到一張網頁,編譯起來只有36KB,運作相當有效率,可以承受一兩千人的同時操作,以實際的Log檔計算,快到學期末時的盤點,約有一千人次上系統,而且連續幾天,系統仍能負荷。這代表著ASP.NET所編譯後的網頁執行效率是相當良好的。
4.9 探討¶
這支程式運行幾年後,有一天與另外一位設計師探討這個問題,他以技術的觀點來看,認為這只不過是顯示及隱藏PANEL的效果而已,並且認為維護會相當的困難。
筆者認為他進入了程式設計師的盲點,究竟是為技術而設計,還是為需求而設計呢?基本上軟體工程就是為了拉近設計與需求之間的距離,並且提供方法讓設計的成果具有重複使用(Reuse)、易維護、穩定的特性。本程式在他看起來會相當難維護,是因他不了解MVC模式,所以對於從介面要找到對應的程式碼,認為相當困難。其實Visual Basic 2005已經提供了由介面找到對應程式碼的功能,只要觀念清楚,命名有規則,這只是滑鼠點選的操作而已。
當然最後該名程式設計師坦承軟體工程他一直學不起來,其實筆者認微軟體工程類似數學的抽象概念,透過抽象概念去描述問題,因此會有許多的專有名詞,就像是數學有許多的專有名詞一樣,入門會遇到瓶頸,可是只要多看多研究,了解專有名詞的意義之後,就會成為您生活上的用語,進而實踐。
設計程式的介面(IDE)至今已經有了相當便利的功能,而且有許多的選擇,因此能夠協助設計者更進一步將焦點放在需求設計上,而非為了技術而去設計程式。
技術是否有用,必須經過眾人的驗證,而且不同時空背景下,應用也有所不同,結果也不同。就像A10戰鬥機上的超音速機槍,早在十九世紀就已經由格林設計出來,但由於笨重,不方便攜帶,因此格林的夢想並沒有實現,隨著戰鬥機的改良,他在十九世紀的設計居然被應用在現代的A10戰鬥機上,而成為坦克殺手。因為超音速技術,所以坦克被打中的時候,只看見一連串的彈孔,而聽不到聲音,當一切都被破壞之後,才能聽到震耳的聲響,這也就是說坦克在死之前連聲音都聽不到。由這個例子來看,技術研發與系統分析設計其實是該從兩種不同角度來觀看,而程式設計師對於不同的案件,應該要能從質性的角度,分析自己的角色,該是由技術研發的觀點還是由設計的觀點來執行工作。
Lai Tai-Yu (賴岱佑)