// 设置最后一个属性页的几个按钮的状态 void SetButtonState(StatisInfo info, bool bSetText = true) { if (info == null) { this.button_statis_crossCompute.Enabled = true; this.button_statis_maskItems.Enabled = false; if (bSetText) this.button_statis_maskItems.Text = "修改册状态"; this.button_statis_return.Enabled = false; if (bSetText) this.button_statis_return.Text = "补做还书"; this.button_statis_outputExcel.Enabled = false; this.button_statis_defOutputColumns.Enabled = false; return; } this.button_statis_crossCompute.Enabled = true; this.button_statis_maskItems.Enabled = true; if (bSetText) this.button_statis_maskItems.Text = "修改册状态 (+" + info.ItemsNeedAddLostState + ", -" + info.ItemsNeedRemoveLostState + ")"; this.button_statis_return.Enabled = true; if (bSetText) this.button_statis_return.Text = "补做还书 (" + info.ItemsNeedReturn + ")"; this.button_statis_outputExcel.Enabled = true; this.button_statis_defOutputColumns.Enabled = true; }
private void button_operLog_load_Click(object sender, EventArgs e) { string strError = ""; if (string.IsNullOrEmpty(this.textBox_operLog_dateRange.Text) == true) { strError = "尚未指定日志日期范围"; goto ERROR1; } this._statisInfo = null; this.SetButtonState(null); ClearHtml(); string strStart = ""; string strEnd = ""; StringUtil.ParseTwoPart(this.textBox_operLog_dateRange.Text, "-", out strStart, out strEnd); string strWarning = ""; List<string> dates = null; int nRet = OperLogStatisForm.MakeLogFileNames(strStart, strEnd, false, // 是否包含扩展名 ".log" out dates, out strWarning, out strError); if (nRet == -1) goto ERROR1; nRet = LoadOperLogs(dates, out strError); if (nRet == -1) goto ERROR1; FillOperLogHtml(); return; ERROR1: MessageBox.Show(this, strError); }
// TODO: 本来就是 丢失 或 注销 状态的册,是否不必给它们加上红色底色? 或者用不同的红色? int DoCrossCompute(out string strError) { strError = ""; int nRet = 0; if (this.listView_inventoryList_records.Items.Count == 0) { strError = "盘点集尚未装载"; return -1; } if (this.listView_baseList_records.Items.Count == 0) { strError = "基准集尚未装载"; return -1; } this._statisInfo = new StatisInfo(); this._statisInfo.ItemsVerified = this.listView_inventoryList_records.Items.Count; this._statisInfo.ItemsBase = this.listView_baseList_records.Items.Count; #if NO string strInventoryDbName = this.MainForm.GetUtilDbName("inventory"); if (string.IsNullOrEmpty(strInventoryDbName) == true) { strError = "尚未定义盘点库"; return -1; } #endif string strInventoryDbName = this._defs.InventoryDbName; int nStateColumnIndex = this._defs._base_colmun_defs.FindColumnByType("item_state"); if (nStateColumnIndex == -1) { strError = "基准集列表中 type 为 item_state 的列没有定义 ..."; return -1; } int nBorrowerColumnIndex = this._defs._base_colmun_defs.FindColumnByType("borrower"); if (nBorrowerColumnIndex == -1) { strError = "基准集列表中 type 为 borrower 的列没有定义 ..."; return -1; } int nTemp = this._defs.source_types.IndexOf("oper_time"); if (nTemp == -1) { strError = "盘点集列表中 type 为 oper_time 的列没有定义 ..."; return -1; } int nOpertimeColumnIndex = this._defs._base_colmun_defs.Count + nTemp + 2; EnableControls(false); stop.OnStop += new StopEventHandler(this.Channel.DoStop); stop.Initial("正在进行交叉运算 ..."); stop.BeginLoop(); this.ShowMessage("正在进行交叉运算 ..."); Application.DoEvents(); try { this.ShowMessage("正在清除标记 ..."); Application.DoEvents(); List<ListViewItem> delete_items = new List<ListViewItem>(); // *** 预备,清除以前的标记 foreach (ListViewItem item in this.listView_baseList_records.Items) { string strState = ListViewUtil.GetItemText(item, nStateColumnIndex + 2); if (string.IsNullOrEmpty(strState) == false && (strState[0] == '+' || strState[0] == '-')) { ListViewUtil.ChangeItemText(item, nStateColumnIndex + 2, strState.Substring(1)); item.Font = this.Font; } if (item.Tag == null) continue; // 需要删除的 item LineType type = (LineType)item.Tag; if (type == LineType.OutOfRange) delete_items.Add(item); item.Tag = null; item.BackColor = SystemColors.Window; } foreach(ListViewItem item in delete_items) { this.listView_baseList_records.Items.Remove(item); } foreach (ListViewItem item in this.listView_inventoryList_records.Items) { item.Tag = null; item.BackColor = SystemColors.Window; } // *** 第一步,准备好记录路径的 Hashtable this.ShowMessage("正在准备 Hashtable ..."); Application.DoEvents(); Hashtable base_recpath_table = new Hashtable(); // recpath --> ListViewItem foreach(ListViewItem item in this.listView_baseList_records.Items) { string strRecPath = item.Text; Debug.Assert(string.IsNullOrEmpty(strRecPath) == false, ""); if (string.IsNullOrEmpty(strRecPath) == false) base_recpath_table[strRecPath] = item; } // *** 第二步,标记盘点过的事项 this.ShowMessage("正在标记盘点册 ..."); Application.DoEvents(); // 获得 册记录路径 的列号 ColumnPropertyCollection temp = this.MainForm.GetBrowseColumnProperties(strInventoryDbName); int nCol = temp.FindColumnByType("item_recpath"); if (nCol == -1) { strError = "盘点库 '"+strInventoryDbName+"' 的 browse 配置文件中未定义 type 为 item_recpath 的列"; return -1; } nCol += 2; // 确保基准列表的列标题个数足够 int nMax = this._defs._base_colmun_defs.Count + 2 + this._defs.source_indices.Count; ListViewUtil.EnsureColumns(this.listView_baseList_records, nMax); List<ListViewItem> outofrange_source_items = new List<ListViewItem>(); // List<string> outof_range_recpaths = new List<string>(); foreach(ListViewItem item in this.listView_inventoryList_records.Items) { string strItemRecPath = ListViewUtil.GetItemText(item, nCol); if (string.IsNullOrEmpty(strItemRecPath) == true) { strError = "发现册记录路径为空的 盘点记录行。操作中断"; return -1; } ListViewItem found = (ListViewItem)base_recpath_table[strItemRecPath]; if (found != null) { // 事项被验证 found.Tag = LineType.Verified; SetLineColor(found, LineType.Verified); // 补充列 AppendColumns(this._defs, found, item); } else { // 事项超出基准集的范围了,设为黄色背景 item.Tag = LineType.OutOfRange; SetLineColor(item, LineType.OutOfRange); outofrange_source_items.Add(item); } } this.ShowMessage("正在标记超范围册 ..."); Application.DoEvents(); // 将超出范围的册记录添加到基准集中 nRet = AddOutOfRangeItemsToBaseList( this._defs, outofrange_source_items, out strError); if (nRet == -1) return -1; this._statisInfo.ItemsOutofRange = nRet; // *** 第三步,标记操作日志中最后动作为 return 的行,这也是一种类似盘点的验证 // 一个册,在盘点动作后时间之后,又发生了借出动作,表明这一册的状态就不是验证过的状态了; // 发生了还回操作表示这是验证过的状态。等于要把盘点动作纳入时间线考察,如果后来被借出代替了就要修改为未验证状态 foreach (OperLogData data in _operLogItems) { ListViewItem found = (ListViewItem)base_recpath_table[data.ItemRecPath]; if (found != null) { if (found.Tag != null) { LineType type = (LineType)found.Tag; if (type == LineType.OutOfRange) continue; } string strOperTime = ListViewUtil.GetItemText(found, nOpertimeColumnIndex); if (string.CompareOrdinal(data.OperTime, strOperTime) < 0) continue; // 只让时间靠后的发生作用 if (data.Action == "return") { // 观察它的状态,如果是超范围的册则不做处理 if (found.Tag != null) { LineType type = (LineType)found.Tag; if (type == LineType.OutOfRange || type == LineType.Verified) continue; } // 事项被验证 found.Tag = LineType.Verified; SetLineColor(found, LineType.Verified); // 补充列。补充操作者 操作时间列 AppendExtraColumns(found, data); this._statisInfo.ItemsVerified++; } if (data.Action == "borrow") { if (found.Tag != null) { LineType type = (LineType)found.Tag; // 把已经处于验证状态的行修改为原始状态 if (type == LineType.Verified) { found.Tag = null; // 表示没有被验证 SetLineColor(found, LineType.Origin); // 补充列。补充操作者 操作时间列 AppendExtraColumns(found, data); this._statisInfo.ItemsVerified--; } } } } } // *** 第四步,标记借出状态的行 标记丢失状态的行 this.ShowMessage("正在标记外借和丢失册 ..."); Application.DoEvents(); this._statisInfo.ItemsBorrowed = 0; this._statisInfo.ItemsLost = 0; this._statisInfo.ItemsNeedAddLostState = 0; foreach(ListViewItem item in this.listView_baseList_records.Items) { // 没有验证过的行 if (item.Tag == null) { #if NO string strBorrower = ""; // 观察借阅者列 // return: // -2 没有找到列 type // -1 出错 // >=0 列号 nRet = GetColumnText(item, "borrower", out strBorrower, out strError); if (nRet == -2 || nRet == -1) return -1; #endif string strBorrower = ListViewUtil.GetItemText(item, nBorrowerColumnIndex + 2); if (string.IsNullOrEmpty(strBorrower) == false) { item.Tag = LineType.Borrowed; this._statisInfo.ItemsBorrowed++; } else { item.Tag = LineType.Lost; this._statisInfo.ItemsLost++; } SetLineColor(item, (LineType)item.Tag); // 进一步判断状态,标注那些新丢失的册 if ((LineType)item.Tag == LineType.Lost) { string strState = ListViewUtil.GetItemText(item, nStateColumnIndex + 2); if (StringUtil.IsInList("丢失", strState) == false && StringUtil.IsInList("注销", strState) == false && string.IsNullOrEmpty(strBorrower) == true) { ListViewUtil.ChangeItemText(item, nStateColumnIndex + 2, "+" + strState); item.Font = new Font(this.Font, FontStyle.Bold); this._statisInfo.ItemsNeedAddLostState++; } } } } // 微调外借状态 // 在盘点期间,最后操作动作为 借 的册,如果先前它曾被盘点验证过,最终也只能算作外借状态的册 // TODO: 如果盘点动作也进入操作日志体系的话,则从操作日志是能精确判断动作先后顺序的。因此能确切知道哪个动作在后。而现在的方法,当盘点完成后如果间隔了一段再进行统计,则册的外借状态就可能会失真了 --- 因为后面可能会发生新的借还操作,还可能不被纳入统计(日志时间)范围 foreach (OperLogData data in _operLogItems) { ListViewItem found = (ListViewItem)base_recpath_table[data.ItemRecPath]; if (found != null && data.Action == "borrow") { if (found.Tag == null) continue; string strBorrower = ListViewUtil.GetItemText(found, nBorrowerColumnIndex + 2); LineType type = (LineType)found.Tag; if (type == LineType.Verified && string.IsNullOrEmpty(strBorrower) == false) { found.Tag = LineType.Borrowed; SetLineColor(found, (LineType)found.Tag); this._statisInfo.ItemsBorrowed++; this._statisInfo.ItemsVerified--; } } } this._statisInfo.ItemsNeedRemoveLostState = 0; this._statisInfo.ItemsNeedReturn = 0; // 检查盘点过的册中,状态值 包含 丢失 和 注销 的,给状态值打上特殊标记,以便提醒操作者可以单独处理它们 foreach (ListViewItem item in this.listView_baseList_records.Items) { if (item.Tag == null) continue; LineType type = (LineType)item.Tag; if (type == LineType.Verified) { string strState = ListViewUtil.GetItemText(item, nStateColumnIndex + 2); if (StringUtil.IsInList("丢失", strState) == true || StringUtil.IsInList("注销", strState) == true) { item.Font = new Font(this.Font, FontStyle.Bold); ListViewUtil.ChangeItemText(item, nStateColumnIndex + 2, "-" + strState); this._statisInfo.ItemsNeedRemoveLostState++; } string strBorrower = ListViewUtil.GetItemText(item, nBorrowerColumnIndex + 2); if (string.IsNullOrEmpty(strBorrower) == false) this._statisInfo.ItemsNeedReturn++; } } SetButtonState(this._statisInfo); this.ShowMessage("完成", "green", true); return 0; } finally { stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.Channel.DoStop); stop.Initial(""); EnableControls(true); } }