编程与数学 03-008 《看潮企业管理软件》项目开发 18 汇总查询 2-2
- 三、窗体功能代码
- 四、窗体功能代码说明
-
- (一)概述
-
- [1.1 功能定位](#1.1 功能定位)
- [1.2 核心特性](#1.2 核心特性)
- (二)技术架构
-
- [2.1 技术栈](#2.1 技术栈)
- [2.2 项目结构](#2.2 项目结构)
- (三)核心功能详解
-
- [3.1 数据载入流程 (Dtzr方法)](#3.1 数据载入流程 (Dtzr方法))
-
- [3.1.1 流程步骤](#3.1.1 流程步骤)
- [3.1.2 条件管理机制](#3.1.2 条件管理机制)
- [3.1.3 缓存策略](#3.1.3 缓存策略)
- [3.2 视图初始化 (Loadgv方法)](#3.2 视图初始化 (Loadgv方法))
-
- [3.2.1 列属性配置](#3.2.1 列属性配置)
- [3.2.2 特殊字段处理](#3.2.2 特殊字段处理)
- [3.2.3 条件样式 (条件显示)](#3.2.3 条件样式 (条件显示))
- [3.3 打印系统 (DoPrintCx方法)](#3.3 打印系统 (DoPrintCx方法))
-
- [3.3.1 打印模板管理](#3.3.1 打印模板管理)
- [3.3.2 数据源结构](#3.3.2 数据源结构)
- [3.3.3 文件字段处理](#3.3.3 文件字段处理)
- [3.4 链接跳转机制](#3.4 链接跳转机制)
-
- [3.4.1 链接配置](#3.4.1 链接配置)
- [3.4.2 跳转逻辑](#3.4.2 跳转逻辑)
- (四)权限控制系统
-
- [4.1 权限字符串格式](#4.1 权限字符串格式)
- [4.2 权限影响的功能](#4.2 权限影响的功能)
- (五)用户界面功能
-
- [5.1 工具栏功能](#5.1 工具栏功能)
- [5.2 右键菜单](#5.2 右键菜单)
- [5.3 快捷键](#5.3 快捷键)
- [5.4 布局保存](#5.4 布局保存)
- (六)数据流与状态管理
-
- [6.1 主要状态变量](#6.1 主要状态变量)
- [6.2 数据生命周期](#6.2 数据生命周期)
- (七)配置与扩展
-
- [7.1 功能配置表](#7.1 功能配置表)
- [7.2 扩展点](#7.2 扩展点)
- [7.3 性能优化建议](#7.3 性能优化建议)
- (八)使用示例
-
- [8.1 创建新的查询功能](#8.1 创建新的查询功能)
- [8.2 常用操作流程](#8.2 常用操作流程)
- (九)故障排除
-
- [9.1 常见问题](#9.1 常见问题)
- [9.2 日志与调试](#9.2 日志与调试)
- 全文总结
摘要:本文介绍了看潮企业管理软件(KcErp)汇总查询功能模型(Uf10Cxhz)的设计与实现。该模块基于DevExpress WinForms框架开发,提供通用数据查询与报表输出平台,支持动态条件配置、多格式打印、智能链接跳转及细粒度权限控制。系统采用SQL模板与数据字典结合实现灵活查询,支持查询结果本地缓存提升性能,并提供可自定义的界面布局与条件样式显示功能,适用于库存、销售、财务等数据的汇总统计需求。
关键词:KcErp;汇总查询;DevExpress;动态SQL;权限控制;数据缓存;打印模板;GridView
人工智能助手:DeepSeek、Kimi
三、窗体功能代码
c#
/*
* 文件名称:Uf10Cxhz.cs
* 功能描述:汇总查询功能模型(Query Summary Module)
* 用途说明:
* 1. 本窗体为ERP系统中的汇总查询通用模块,负责根据预定义的查询条件加载、展示和打印汇总数据。
* 2. 支持载入条件配置、数据查询、表格显示、列宽调整、条件筛选、链接跳转、文件字段操作、打印预览与直接打印等功能。
* 3. 可根据用户权限控制导出、打印、文件操作等行为。
* 4. 支持多模板打印(含卡片、标签等特殊格式)以及数据缓存(XML文件)以提高重复查询性能。
* 5. 集成了右键菜单、快捷键操作(如F4打开链接、Ctrl+数字锁定列)、单元格样式定制等增强交互功能。
* 6. 与系统菜单、权限体系、数据字典、打印模板等模块紧密集成,为ERP提供统一的查询与报表输出界面。
* 主要类:Uf10Cxhz(DevExpress.XtraEditors.XtraForm)
* 依赖模块:DevExpress UI组件、KcErp业务模块、数据库访问层(KcDb)、打印服务(XtraReport)等。
*/
using DevExpress.Utils;
using DevExpress.Utils.Menu;
using DevExpress.XtraBars;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraReports.UI;
using System;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using static KcErp.KcDb;
using static KcErp.KcDybjsb;
using static KcErp.KcEditfm;
using static KcErp.KcEditgd;
using static KcErp.KcFile;
using static KcErp.KcMain;
namespace KcErp
{
public partial class Uf10Cxhz : DevExpress.XtraEditors.XtraForm
{
#region dim public
public string fgnbh; // 功能编号
public string fgnmc; // 功能名称
public string ft1; // 功能表1(主数据表)
public string ftbb; // 功能表版本
public string ftcxbt; // 查询标题
public string ftcxljzd; // 查询链接字段(用于跳转其他功能)
public string ftglzd; // 过滤字段(允许筛选的列)
public string ftmbgltj; // 模板关联条件(打印模板与条件的关联字段)
public string ftpxzd; // 排序字段
public string ftsql; // 查询SQL语句
public string ftyczd; // 隐藏字段(不显示的列)
public string ftzdyb; // 字典原表(关联的数据字典表)
public string fxz; // 限制权限(字符串格式,每位代表一种权限)
bool avend = false; // 是否已结束
string dcbt = ""; // 导出标题
string dcsql = ""; // 导出SQL
DataTable dt1; // 主数据表
DataTable dttj1; // 条件数据表(载入条件)
DataTable dttjxs; // 条件显示样式表(用于定制单元格外观)
bool fh = false; // 是否返回
string ft1wjzd = ""; // 文件字段列表(如表中的附件字段)
GridView gdgv = new GridView(); // 网格视图对象
bool gvend = false; // 网格视图是否已结束
bool jsing = false; // 是否正在计算
string jszdstr = ""; // 计算字段列表字符串
string jzzd = ""; // 禁止字段(不加载的字段)
bool loaderr = false; // 加载过程中是否发生错误
bool loading = false; // 是否正在加载数据
bool lvend = false; // 列表视图是否已结束
RepositoryItemButtonEdit[] rcbt; // 按钮编辑仓库项数组(用于链接列)
string[] rcbtmc; // 按钮标题数组(链接功能名称)
RepositoryItemTextEdit rctt = new RepositoryItemTextEdit(); // 文本编辑仓库项(默认编辑器)
bool sfgv; // 是否使用GridView视图
bool sfplay = false; // 是否正在播放(未使用)
bool sfzr; // 是否已载入数据
string sqltj; // 条件SQL
bool xzbj; // 是否允许编辑(权限位)
bool xzck; // 是否允许查看(权限位)
bool xzdc; // 是否允许导出(权限位)
bool xzdy; // 是否允许打印(权限位)
bool xzwj; // 是否允许文件操作(权限位)
string zrtjstr = ""; // 载入条件字符串(用于缓存标识)
#endregion dim public
public Uf10Cxhz()
{
InitializeComponent();
this.Load += Form_load; // 窗体加载事件
BarZR.ItemClick += Barzr_itemclick; // 载入按钮点击事件
// Bar 按钮事件绑定
BarHelp.ItemClick += BarHelp_ItemClick;
Barexit.ItemClick += BarExit_ItemClick;
BarPrint.ItemClick += BarPrint_ItemClick;
BarPreview.ItemClick += BarPreview_ItemClick;
// 窗体事件
this.Disposed += Form_hzcx_disposed; // 窗体销毁事件
this.FormClosed += Form_CXHZ_FormClosed; // 窗体关闭事件
}
/// <summary>
/// 根据权限和状态启用或禁用工具栏按钮
/// </summary>
private void Barenabled()
{
BarZR.Enabled = true; // 载入按钮始终启用
BarPreview.Enabled = sfzr && xzdy; // 预览需已载入且有打印权限
BarPrint.Enabled = sfzr && xzdy; // 打印需已载入且有打印权限
}
/// <summary>
/// 退出按钮点击事件:保存窗口设置、释放资源并关闭窗体
/// </summary>
private void BarExit_ItemClick(object sender, ItemClickEventArgs e)
{
try
{
SaveFmSet(); // 保存窗口和表格布局
fh = true; // 标记为返回状态
dt1?.Dispose(); // 释放数据表资源
dttj1?.Dispose();
Close(); // 关闭窗体
}
catch (Exception ex)
{
MsgExShow("返回上级窗口", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 帮助按钮点击事件:打开当前功能的帮助信息
/// </summary>
private void BarHelp_ItemClick(object sender, ItemClickEventArgs e)
{
RunHelpyy(this, fgnmc, pSFSJ);
}
/// <summary>
/// 打印预览按钮点击事件:调用打印功能,预览模式
/// </summary>
private void BarPreview_ItemClick(object sender, ItemClickEventArgs e)
{
DoPrintCx(false);
}
/// <summary>
/// 直接打印按钮点击事件:调用打印功能,直接打印模式
/// </summary>
private void BarPrint_ItemClick(object sender, ItemClickEventArgs e)
{
DoPrintCx(true);
}
/// <summary>
/// 载入按钮点击事件:执行数据载入流程
/// </summary>
private void Barzr_itemclick(object sender, ItemClickEventArgs e)
{
Dtzr();
}
/// <summary>
/// 执行打印或预览操作
/// </summary>
/// <param name="sfdy">是否直接打印(true为直接打印,false为预览)</param>
private void DoPrintCx(bool sfdy)
{
try
{
// 1. 检查模板
if (Bardymb.EditValue == null)
{
MsgOxShow("没有可用的打印模板");
return;
}
string mbName = Bardymb.EditValue.ToString().Trim();
if (string.IsNullOrEmpty(mbName))
{
MsgOxShow("没有可用的打印模板");
return;
}
if (mbName == "直接打印")
{
// 直接打印模式:使用GridView自带的打印预览
gdgv.OptionsPrint.AllowCancelPrintExport = true;
gdgv.ShowRibbonPrintPreview();
return;
}
// 2. 读取模板
MemoryStream dyStream = Mbstream(mbName);
if (dyStream == null)
{
MsgOxShow("打印模板没有找到");
return;
}
XtraReport xr = XtraReport.FromXmlStream(dyStream, true);
if (xr == null)
{
MsgOxShow("打印模板没有设计完成");
return;
}
xr.Name = mbName;
xr.PrinterName = pPrinterName;
bool sfbq = mbName.Contains("卡片") || mbName.Contains("标签"); // 判断是否为标签/卡片打印
// 3. 构造数据源
DataSet ds = new DataSet("dataset1");
// 3.1 表 t1:存放查询标题和条件结果(一行)
DataTable dstb1 = new DataTable("t1");
dstb1.Columns.Add("btmc", typeof(string)).DefaultValue = "";
foreach (DataRow r in dttj1.Rows)
{
string colName = r["tjmc"].ToString();
dstb1.Columns.Add(colName, typeof(string)).DefaultValue = "";
}
DataRow t1Row = dstb1.NewRow();
t1Row["btmc"] = LCBT.Text;
foreach (DataRow r in dttj1.Rows)
t1Row[r["tjmc"].ToString()] = r["tjjg"];
dstb1.Rows.Add(t1Row);
dstb1.AcceptChanges();
ds.Merge(dstb1);
// 3.2 表 t2:存放详细数据
DataTable dstb2;
if (sfbq)
{
// 标签打印:只打印当前选中行
int bqRowIndex = gdgv.GetFocusedDataSourceRowIndex();
dstb2 = dt1.Clone();
if (bqRowIndex >= 0)
{
DataRow newRow = dstb2.NewRow();
for (int c = 0; c < dstb2.Columns.Count; c++)
newRow[c] = dt1.Rows[bqRowIndex][c];
dstb2.Rows.Add(newRow);
}
}
else
{
// 普通打印:打印所有行
dstb2 = dt1.Clone();
DataView dv = new DataView(dt1);
foreach (DataRowView rv in dv)
{
DataRow newRow = dstb2.NewRow();
Copyrow(newRow, rv);
dstb2.Rows.Add(newRow);
}
}
// 3.3 下载文件字段:将数据库中的文件路径转换为本地临时文件路径
string t1wjzd = "tp1,tp2,tp3,wj1,wj2,wj3"; // 默认支持的图片和文件字段
if (!string.IsNullOrEmpty(ft1wjzd))
{
string[] wjzd = $"{ft1wjzd},{t1wjzd}".Split(',');
wjzd = wjzd.Where(s => dstb2.Columns.Contains(s)).ToArray();
foreach (string fld in wjzd)
{
if (string.IsNullOrWhiteSpace(fld)) continue;
foreach (DataRow r in dstb2.Rows)
{
object val = r[fld];
if (val == null || val == DBNull.Value) continue;
string fileName = val.ToString();
if (string.IsNullOrWhiteSpace(fileName)) continue;
// 下载文件到本地缓存目录
FileOL_Down(this, ft1, fld, fileName);
r[fld] = Path.Combine(pFilesLC, fileName);
}
}
}
dstb2.TableName = "t2";
dstb2.AcceptChanges();
ds.Merge(dstb2);
xr.DataSource = ds;
// 4. 标记识别 & 打印
DyBjSb(ref xr); // 打印标记识别(如条形码、二维码等)
if (sfdy)
xr.Print();
else
xr.ShowPreviewDialog();
}
catch (Exception ex)
{
MsgExShow("准备打印数据", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 数据载入主流程:加载条件、执行查询、绑定表格、应用设置
/// </summary>
private void Dtzr()
{
try
{
L3.Caption = "";
loading = true;
string sqltj1;
string sql1;
bool sfcxcx = pCXCX; // 是否重新查询(系统配置)
// 1. 加载用户保存的查询条件
dttj1 = new DataTable();
sqltj1 = "select dyid,tjxh,tjmc,tjjg,tjsm,tjedit,rxkz from x9_gn_0zrtj nolock where gnbh='" + fgnbh + "' and yhmc='" + pDQYH + "' order by tjxh";
dttj1 = KcDb.DtRead(sqltj1);
if (dttj1.Rows.Count <= 0)
{
// 如果没有保存的条件,则调用存储过程初始化
KcDb.DBexec("select x9_zrtjcs('" + fgnbh + "','" + pDQYH + "')");
dttj1 = KcDb.DtRead(sqltj1);
}
// 2. 显示条件编辑窗体(如果存在条件)
if (dttj1.Rows.Count > 0)
{
FmZRTJ fmtj = new FmZRTJ();
fmtj.Text = fgnmc + "载入条件";
fmtj.fgnbh = fgnbh;
fmtj.fgnmc = fgnmc;
fmtj.sfcxhz = true;
fmtj.Loadtjfm();
fmtj.Tjedit(ref dttj1);
dttj1.AcceptChanges();
fmtj.ShowDialog(this);
if (!fmtj.sfok)
{
// 用户取消,则关闭窗口(如果是首次载入)
if (!sfzr)
this.Close();
return;
}
Zrtjsave(fmtj.tjlc, ref dttj1);
DataTable udt1 = dttj1.GetChanges();
if (udt1 != null)
{
// 保存修改后的条件到数据库
if (KcDb.GetDtSavev("x9_gn_0zrtj", ref udt1, "tjjg"))
{
dttj1.AcceptChanges();
}
}
sfcxcx = fmtj.sfcxcx; // 是否重新查询(用户选择)
fmtj.Close();
fmtj.Dispose();
}
this.Focus();
// 3. 构造查询SQL
sql1 = TjStr(ref dttj1, ftsql); // 将条件替换到SQL模板中
string cxbs = fgnmc;
LCBT.Text = TjStr(ref dttj1, ftcxbt); // 生成查询标题
for (int i = 0; i < dttj1.Rows.Count; i++)
{
string tjedit = dttj1.Rows[i]["tjedit"].ToString();
switch (tjedit)
{
case "dateedit":
DateTime tjdate;
try
{
tjdate = Convert.ToDateTime(dttj1.Rows[i]["tjjg"]);
}
catch
{
tjdate = Getywdate(); // 获取业务默认日期
}
zrtjstr += dttj1.Rows[i]["tjmc"].ToString() + "@" + tjdate.ToString("yyyy-MM-dd") + "@";
cxbs += tjdate.ToString("yyyy-MM-dd");
break;
default:
zrtjstr += dttj1.Rows[i]["tjmc"].ToString() + "@" + dttj1.Rows[i]["tjjg"].ToString() + "@";
cxbs += dttj1.Rows[i]["tjjg"].ToString();
break;
}
}
cxbs = Hfwjm(cxbs); // 生成缓存文件名(避免非法字符)
dcsql = sql1;
dcbt = LCBT.Text;
dt1 = new DataTable();
string qrname = pFilesQuery + "\\" + pDBmc + cxbs;
bool wjzr = false;
// 4. 尝试从缓存文件加载数据(如果允许且文件存在)
if (!sfcxcx)
{
if (File.Exists(qrname + ".xml") && File.Exists(qrname + ".xmlschema"))
{
dt1.ReadXmlSchema(qrname + ".xmlschema");
dt1.ReadXml(qrname + ".xml");
if (dt1 != null && dt1.Rows.Count > 0)
{
wjzr = true; // 标记为文件载入
}
}
}
// 5. 如果未从文件载入,则从数据库查询
if (!wjzr)
{
dt1 = KcDb.DtRead(sql1);
}
if (dt1 == null)
{
MsgXxShow("数据未能正确载入,请检查功能定义是否完整或载入过程是否正确");
if (!sfzr)
this.Close();
return;
}
else
{
// 检查是否为错误信息(单行单列的特殊情况)
if (dt1.Rows.Count == 1 && dt1.Columns.Count == 1)
{
Barenabled();
MsgXxShow("数据未能正确载入," + dt1.Rows[0][0].ToString());
if (!sfzr)
this.Close();
return;
}
// 6. 缓存查询结果到XML文件(如果是新查询)
if (!wjzr)
{
try
{
dt1.WriteXmlSchema(qrname + ".xmlschema");
dt1.WriteXml(qrname + ".xml");
}
catch (Exception ex)
{
MsgExShow("保存文件", ex.Message, ex.Source, ex.StackTrace);
}
}
// 7. 如果是设计模式,记录SQL用于调试或文档
if (pSFSJ)
{
string sql0 = "select '" + LCBT.Text + "' as btmc";
for (int r = 0; r < dttj1.Rows.Count; r++)
{
sql0 += ",'" + dttj1.Rows[r]["tjjg"].ToString() + "' as " + dttj1.Rows[r]["tjmc"].ToString();
}
string t1 = sql0.Replace("'", "`");
string t2 = sql1.Replace("'", "`");
string d1 = "";
string d2 = ("select * from x9_sjzd where tname='" + ft1 + "' and zdbb ='" + ftbb + "'").Replace("'", "`");
KcDb.DBexec("update x9_gn_0dymb set t1='" + t1 + "',t2='" + t2 + "',d1='" + d1 + "',d2='" + d2 +
"' where gnbh='" + fgnbh + "' and sjsd=false");
}
// 8. 移除禁止字段(jzzd)
string[] jz = jzzd.Split(',');
for (int c = dt1.Columns.Count - 1; c >= 1; c--)
{
for (int j = 0; j < jz.Length; j++)
{
if (dt1.Columns[c].ColumnName.ToLower() == jz[j].ToLower())
{
dt1.Columns.RemoveAt(c);
break;
}
}
}
// 9. 绑定数据到GridControl
GridView1.OptionsBehavior.AutoPopulateColumns = false;
GridCX.DataSource = dt1;
// 10. 根据模板关联条件自动选择打印模板
if (!string.IsNullOrEmpty(ftmbgltj))
{
DataRow[] glrow = dttj1.Select("tjmc='" + ftmbgltj + "'");
if (glrow.Length > 0)
{
string glmb = glrow[0]["tjjg"].ToString();
if (Rcdymb.Items.IndexOf(glmb) >= 0)
{
Bardymb.EditValue = glmb;
}
}
}
// 11. 初始化GridView
Loadgv();
sfgv = true;
sfzr = true; // 标记为已载入
}
Barenabled();
KcDb.DBclose();
}
catch (Exception ex)
{
sfzr = true;
loaderr = true;
MsgExShow("载入数据", ex.Message, ex.Source, ex.StackTrace);
}
if (loaderr)
{
MsgXxShow("加载功能时出错,请检查功能设计的正确性");
this.Close();
return;
}
try
{
// 12. 应用保存的窗口和表格布局
if (gdgv != null)
{
string fmset = FmRead(fgnmc);
string[] fmay = fmset.Split(',');
if (fmay.Length >= 5)
{
short ws = 0;
if (fmay.Length == 6)
{
ws = Convert.ToInt16(fmay[5]);
if (ws == 2)
this.WindowState = FormWindowState.Maximized;
if (ws == 0)
{
if (Convert.ToInt32(fmay[0]) > 0) this.Top = Convert.ToInt32(fmay[0]);
if (Convert.ToInt32(fmay[1]) > 0) this.Left = Convert.ToInt32(fmay[1]);
if (Convert.ToInt32(fmay[2]) > 50) this.Width = Convert.ToInt32(fmay[2]);
if (Convert.ToInt32(fmay[3]) > 50) this.Height = Convert.ToInt32(fmay[3]);
}
}
if (sfzr && gdgv != null)
{
if (Convert.ToInt32(fmay[4]) > 20)
gdgv.RowHeight = Convert.ToInt32(fmay[4]);
else
gdgv.RowHeight = 28;
}
}
// 列宽设置
fmset = FmRead(fgnmc + "表格");
fmay = fmset.Split(',');
if (fmay.Length == gdgv.Columns.Count)
{
for (int c = 0; c < gdgv.Columns.Count; c++)
{
int cw = Convert.ToInt32(fmay[c]);
if (cw <= 0)
gdgv.Columns[c].Visible = false;
else
gdgv.Columns[c].Width = cw;
}
}
else
{
// 自动调整列宽
Gvoptionwith(ref gdgv, GridCX.Width);
}
L3.Caption = "共载入[" + dt1.Rows.Count.ToString().Trim() + "]行记录";
}
this.Show();
}
catch (Exception ex)
{
MsgExShow("应用保存的窗口参数", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 自动配置列宽菜单项点击事件
/// </summary>
private void Dxmenuclick(object sender, EventArgs e)
{
Gvoptionwith(ref gdgv, GridCX.Width);
}
/// <summary>
/// 手动配置列宽菜单项点击事件
/// </summary>
private void Dxsdclick(object sender, EventArgs e)
{
Gvsdoption(ref gdgv);
}
/// <summary>
/// 文件字段按钮点击事件:打开文件编辑对话框
/// </summary>
private void File_buttonclick(object sender, ButtonPressedEventArgs e)
{
try
{
FileOL_edit(this, e.Button.Caption, ft1, e.Button.Tag.ToString(), "", sender as ButtonEdit);
}
catch (Exception ex)
{
MsgExShow("文件编辑", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 窗体加载事件:初始化数据库连接、界面元素、权限、打印模板等
/// </summary>
private void Form_load(object sender, EventArgs e)
{
try
{
// 检查数据库连接
if (KcDb.KcCn.State != ConnectionState.Open)
{
KcDb.DBLJ();
if (!KcDb.SFlj)
{
MsgXxShow("账套数据库未能连接,请在主窗口重试!");
this.Close();
return;
}
}
SetDg(this, 1360, 600, true);
RibbonControl.ApplicationCaption = fgnmc;
RibbonPage1.Text = fgnmc;
// 加载菜单图标
if (pCdimage.Images.Count > 0)
{
for (int i = 0; i < RibbonControl.Items.Count; i++)
{
if (RibbonControl.Items[i].GetType().Name.ToLower() == "barbuttonitem")
{
if (pCdimage.Images.IndexOf(RibbonControl.Items[i].Caption) >= 0)
{
RibbonControl.Items[i].LargeGlyph = pCdimage.Images[RibbonControl.Items[i].Caption];
}
}
}
}
}
catch (Exception ex)
{
loaderr = true;
MsgExShow("加载菜单图标", ex.Message, ex.Source, ex.StackTrace);
}
try
{
LCBT.Text = fgnmc;
// 加载报表模板列表
Rcdymb.Items.Clear();
Rcdymb.TextEditStyle = TextEditStyles.DisableTextEditor;
DataTable dtbb = new DataTable();
dtbb = KcDb.DtRead("select mbmc as bbmb from x9_gn_0dymb where gnbh= '" + fgnbh + "' and ((czry like '%" + pDQYH + "%') or czry='') order by mbxh");
if (dtbb != null)
{
if (dtbb.Rows.Count > 0)
{
for (int i = 0; i < dtbb.Rows.Count; i++)
{
Rcdymb.Items.Add(dtbb.Rows[i]["bbmb"].ToString());
}
}
}
Rcdymb.Items.Add("直接打印");
if (Rcdymb.Items.Count > 0)
{
Bardymb.EditValue = Rcdymb.Items[0].ToString();
}
// 解析权限字符串(fxz格式如 "01101")
xzdy = fxz.Substring(1, 1) == "1";
xzwj = fxz.Substring(3, 1) == "1";
xzdc = fxz.Substring(4, 1) == "1"; // 导出致xml文件,加密
// 获取禁止字段列表
DataRow[] dr = pDTQX.Select("gnbh='" + fgnbh + "'");
if (dr.Length > 0)
{
jzzd = dr[0]["jzzd"].ToString().Trim();
}
RcCZJL.Items.Clear();
L1.Caption = "[" + fgnmc + "]";
L2.Caption = "[当前用户:" + pDQYH + "]";
R1.Caption = "";
R2.Caption = "[" + pZTMC + "]";
GridCX.RepositoryItems.Add(rctt);
}
catch (Exception ex)
{
loaderr = true;
MsgExShow("加载窗口", ex.Message, ex.Source, ex.StackTrace);
}
if (loaderr)
{
this.Close();
return;
}
try
{
// 加载条件显示样式表(用于定制单元格颜色等)
dttjxs = KcDb.DtRead("select * from x9_gn_tjxs where gnbh='" + fgnbh + "'");
}
catch (Exception ex)
{
MsgExShow("加载条件显示数据", ex.Message, ex.Source, ex.StackTrace);
}
// 执行数据载入
Dtzr();
if (!sfzr)
return;
}
/// <summary>
/// 自定义单元格编辑器:根据链接字段的值动态分配按钮编辑器
/// </summary>
private void Gdgv_customrowcelledit(object sender, CustomRowCellEditEventArgs e)
{
try
{
if (e.Column.FieldName != ftcxljzd)
return;
if (string.IsNullOrWhiteSpace(e.CellValue?.ToString()))
{
e.RepositoryItem = rctt; // 空值使用普通文本编辑器
}
else
{
int i = Array.IndexOf(rcbtmc, e.CellValue.ToString().Trim());
if (i >= 0)
e.RepositoryItem = rcbt[i]; // 匹配的按钮编辑器
else
e.RepositoryItem = rctt;
}
}
catch { }
}
/// <summary>
/// 网格视图右键菜单显示前事件:添加自定义菜单项(自动/手动配置列宽)
/// </summary>
private void Gdgv_popupmenushowing(object sender, PopupMenuShowingEventArgs e)
{
try
{
bool ists = false;
foreach (DXMenuItem mi in e.Menu.Items)
{
if (mi.Caption == "自动配置列宽")
{
ists = true;
break;
}
}
if (!ists)
{
DXMenuItem dxmenu = new DXMenuItem();
dxmenu.Caption = "自动配置列宽";
dxmenu.Click += Dxmenuclick;
e.Menu.Items.Add(dxmenu);
DXMenuItem dxmenusd = new DXMenuItem();
dxmenusd.Caption = "手动配置列宽";
dxmenusd.Click += Dxsdclick;
e.Menu.Items.Add(dxmenusd);
}
}
catch (Exception ex)
{
MsgExShow("增加配置列宽右键菜单", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 窗体关闭事件:激活其他打开的窗体
/// </summary>
private void Form_CXHZ_FormClosed(object sender, FormClosedEventArgs e)
{
Form dqfm = null;
foreach (Form opfm in Application.OpenForms)
{
opfm.WindowState = FormWindowState.Normal;
dqfm = opfm;
}
if (dqfm != null)
dqfm.Activate();
}
/// <summary>
/// 窗体销毁事件:释放所有资源,防止内存泄漏
/// </summary>
private void Form_hzcx_disposed(object sender, EventArgs e)
{
try
{
// 清空所有字段和引用
ft1 = null;
ftbb = null;
fxz = null;
fgnbh = null;
fgnmc = null;
ftsql = null;
ftglzd = null;
ftpxzd = null;
ftmbgltj = null;
ftcxbt = null;
ftcxljzd = null;
ftyczd = null;
ftzdyb = null;
xzbj = false;
xzdy = false;
xzck = false;
xzwj = false;
xzdc = false;
jzzd = null;
sqltj = null;
dt1 = null;
dttj1 = null;
sfzr = false;
gvend = false;
lvend = false;
avend = false;
sfgv = false;
dttjxs = null;
gdgv = null;
jszdstr = null;
jsing = false;
loading = false;
sfplay = false;
rctt = null;
rcbt = null;
rcbtmc = null;
fh = false;
dcsql = null;
dcbt = null;
zrtjstr = null;
ft1wjzd = null;
loaderr = false;
RibbonControl = null;
RibbonPage1 = null;
Rp1 = null;
Rp5 = null;
Rp4 = null;
RibbonStatusBar = null;
BarZR = null;
GridCX = null;
GridView1 = null;
L1 = null;
L2 = null;
RepositoryItemRadioGroup1 = null;
V1 = null;
V2 = null;
CardView1 = null;
BackgroundWorker1 = null;
BarPrint = null;
BarPreview = null;
BarHelp = null;
OpenFileDialog1 = null;
RcCZJL = null;
Barexit = null;
LCBT = null;
R1 = null;
R2 = null;
L3 = null;
Bardymb = null;
Rcdymb = null;
GC.Collect(); // 强制垃圾回收
}
catch (Exception ex)
{
MsgExShow("亢墮完笥斤嵆", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 链接字段按钮点击事件:跳转到关联功能(如单据查询)
/// </summary>
private void Ljcx_buttonclick(object sender, ButtonPressedEventArgs e)
{
string ljstr = gdgv.GetRowCellValue(gdgv.FocusedRowHandle, gdgv.FocusedColumn).ToString();
if (string.IsNullOrWhiteSpace(ljstr))
{
MsgOxShow("没有对应的链接数据");
return;
}
try
{
string ljgnbh;
string ljgnmc = e.Button.Caption;
string sqlljtj;
DataTable dtljtj = new DataTable();
DataRow[] dr = pDTQX.Select("gnmc='" + ljgnmc + "'");
if (dr.Length > 0)
{
string mxqx = dr[0]["xzqx"].ToString();
ljgnbh = dr[0]["gnbh"].ToString();
// 加载目标功能的载入条件
sqlljtj = "select dyid,tjxh,tjmc,tjjg,tjsm,tjedit,rxkz from x9_gn_0zrtj nolock where gnbh='" + ljgnbh + "' and yhmc='" + pDQYH + "' order by tjxh";
dtljtj = KcDb.DtRead(sqlljtj);
if (dtljtj.Rows.Count <= 0)
{
KcDb.DBexec("select x9_zrtjcs('" + ljgnbh + "','" + pDQYH + "')");
dtljtj = KcDb.DtRead(sqlljtj);
}
// 替换当前查询条件:将本功能的查询条件值赋给目标功能
string[] tjcc = new string[dttj1.Rows.Count];
string[] tjvv = new string[dttj1.Rows.Count];
for (int l = 0; l < dttj1.Rows.Count; l++)
{
tjcc[l] = dttj1.Rows[l]["tjmc"].ToString();
tjvv[l] = dttj1.Rows[l]["tjjg"].ToString();
}
for (int r = 0; r < dtljtj.Rows.Count; r++)
{
string tjmc = dtljtj.Rows[r]["tjmc"].ToString().Trim();
int tjcol = Array.IndexOf(tjcc, tjmc);
if (tjcol >= 0)
dtljtj.Rows[r]["tjjg"] = tjvv[tjcol];
else
dtljtj.Rows[r]["tjjg"] = "";
}
// 替换当前行条件:将当前行对应列的值赋给目标功能条件
string[] cc = new string[gdgv.Columns.Count];
string[] cf = new string[gdgv.Columns.Count];
string[] vv = new string[gdgv.Columns.Count];
for (int l = 0; l < gdgv.Columns.Count; l++)
{
cc[l] = gdgv.Columns[l].Caption;
cf[l] = gdgv.Columns[l].FieldName;
vv[l] = gdgv.GetRowCellValue(gdgv.FocusedRowHandle, gdgv.Columns[l]).ToString();
}
for (int r = 0; r < dtljtj.Rows.Count; r++)
{
string tjmc = dtljtj.Rows[r]["tjmc"].ToString().Trim();
int tjcol = Array.IndexOf(cc, tjmc);
if (tjcol >= 0)
dtljtj.Rows[r]["tjjg"] = vv[tjcol];
tjcol = Array.IndexOf(cf, tjmc);
if (tjcol >= 0)
dtljtj.Rows[r]["tjjg"] = vv[tjcol];
}
// 提交条件到数据库
DataTable udt1 = dtljtj.GetChanges();
if (udt1 != null)
{
if (KcDb.GetDtSavev("x9_gn_0zrtj", ref udt1, "tjjg"))
{
dtljtj.AcceptChanges();
}
}
string ljfl = dr[0]["gnly"].ToString();
string[] cxoid = new string[1];
if (ljfl == "单据查询")
{
// 单据查询需要传递oid(单据号)列表
if (dt1.Columns.IndexOf("oid") > -1)
{
cxoid = new string[dt1.Rows.Count];
int s = -1;
for (int r = 0; r < dt1.Rows.Count; r++)
{
if (dt1.Rows[r][ftcxljzd].ToString() == ljgnmc)
{
string str = dt1.Rows[r]["oid"].ToString();
if (!string.IsNullOrEmpty(str) && Array.IndexOf(cxoid, str) < 0)
{
s++;
cxoid[s] = str;
}
}
}
if (s >= 0)
{
Array.Resize(ref cxoid, s + 1);
string dqoid = gdgv.GetRowCellValue(gdgv.FocusedRowHandle, gdgv.Columns["oid"]).ToString();
X9gn(ljgnmc, ljfl, ljgnbh, mxqx, cxoid, dqoid);
}
else
{
MsgOxShow("链接单据查询,请在查询设计时包含单据号字段oid");
return;
}
}
else
{
MsgOxShow("链接单据查询,请在查询设计时包含单据号字段oid");
return;
}
}
else
{
// 其他类型功能直接打开
X9gn(ljgnmc, ljfl, ljgnbh, mxqx, null, null);
}
}
else
{
MsgOxShow("当前操作员无此权限");
}
KcDb.DBclose();
}
catch (Exception ex)
{
MsgExShow("调用链接功能", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 初始化GridView:绑定列属性、设置编辑器、链接字段、样式等
/// </summary>
private void Loadgv()
{
// 初始gv
try
{
if (dt1 == null)
{
loaderr = true;
return;
}
if (GridCX == null)
{
loaderr = true;
return;
}
if (GridCX.ViewCollection.Count == 0)
{
gdgv = new GridView(GridCX);
gdgv.Name = "gdgv";
}
gdgv.BeginUpdate();
gdgv.OptionsBehavior.AutoPopulateColumns = false;
GridCX.DataSource = dt1;
// 检查链接字段是否存在
if (dt1.Columns.IndexOf(ftcxljzd) < 0)
{
ftcxljzd = "";
}
GridCX.MainView = gdgv;
gdgv.PopulateColumns();
SetGv(ref gdgv, false);
gdgv.PopupMenuShowing += Gdgv_popupmenushowing;
gdgv.OptionsSelection.MultiSelect = true;
gdgv.OptionsSelection.MultiSelectMode = GridMultiSelectMode.RowSelect;
gdgv.OptionsView.EnableAppearanceEvenRow = true;
gdgv.OptionsView.EnableAppearanceOddRow = true;
// 加载数据字典(列属性)
string zdsql;
DataTable dtzd = new DataTable();
zdsql = "select * from x9_sjzd nolock where zdbb='" + ftbb + "' and tname in ('" + ft1 + "','" + ftzdyb.Replace(",", "','") + "') order by fxh";
dtzd = KcDb.DtRead(zdsql);
if (dtzd != null)
{
if (dtzd.Rows.Count > 0)
{
// 根据字典设置列属性(编辑器、格式、标题等)
Gdloread(ref GridCX, ref gdgv, ref dtzd, xzwj);
gdgv.CustomDrawCell += View_tjxs; // 绑定单元格绘制事件(条件显示样式)
string ctag;
string[] artag = "fileedit,fileread,buttontextedit,buttontextread,hyperlinkedit".Split(',');
string[] px = ftpxzd.ToLower().Split(',');
string[] gl = ftglzd.ToLower().Split(',');
for (int col = 0; col < gdgv.Columns.Count; col++)
{
string fd = gdgv.Columns[col].FieldName.ToLower();
// 隐藏字段处理
if (ftyczd.IndexOf(fd) >= 0)
{
gdgv.Columns[col].Visible = false;
continue;
}
// 允许排序字段
if (Array.IndexOf(px, fd) >= 0)
{
gdgv.Columns[col].OptionsColumn.AllowSort = DefaultBoolean.True;
}
// 允许筛选字段
if (Array.IndexOf(gl, fd) >= 0)
{
gdgv.Columns[col].OptionsFilter.AllowFilter = true;
}
string[] ttag = gdgv.Columns[col].Tag.ToString().Split(',');
if (ttag.Length > 1 && ttag[1] != "")
{
// 绑定F4快捷键事件(用于打开搜索链接)
RepositoryItem ri = gdgv.Columns[col].ColumnEdit as RepositoryItem;
if (ri != null)
{
ri.KeyUp += View_keyf4;
}
}
ctag = ttag[0];
if (Array.IndexOf(artag, ctag) < 0)
continue;
// 根据列类型绑定相应事件
switch (ctag)
{
case "fileedit":
case "fileread":
RepositoryItemButtonEdit rcFile = gdgv.Columns[col].ColumnEdit as RepositoryItemButtonEdit;
if (rcFile != null)
{
rcFile.ButtonClick += File_buttonclick;
}
if (ft1wjzd == "")
ft1wjzd = gdgv.Columns[col].FieldName;
else
ft1wjzd += "," + gdgv.Columns[col].FieldName;
break;
case "buttontextedit":
case "buttontextread":
RepositoryItemButtonEdit rcText = gdgv.Columns[col].ColumnEdit as RepositoryItemButtonEdit;
if (rcText != null)
{
rcText.ButtonClick += Text_buttonclick;
}
break;
case "hyperlinkedit":
RepositoryItemTextEdit rcLink = gdgv.Columns[col].ColumnEdit as RepositoryItemTextEdit;
if (rcLink != null)
{
rcLink.KeyUp += View_keylink;
}
break;
}
}
gdgv.KeyDown += View_keydown; // 绑定键盘事件(列宽调整、锁定列)
GridCX.UseEmbeddedNavigator = false;
gdgv.KeyUp += View_keyf4;
// 准备链接字段的按钮编辑器
string btmc = "";
string dqmc = "";
if (!string.IsNullOrEmpty(ftcxljzd))
{
for (int r = 0; r < gdgv.RowCount; r++)
{
dqmc = gdgv.GetRowCellValue(r, gdgv.Columns[ftcxljzd]).ToString().Trim();
if (!string.IsNullOrEmpty(dqmc) && btmc.IndexOf(dqmc) < 0)
{
btmc += dqmc + "`";
}
}
}
if (!string.IsNullOrEmpty(btmc))
{
rcbtmc = btmc.Substring(0, btmc.Length - 1).Split('`');
rcbt = new RepositoryItemButtonEdit[rcbtmc.Length];
for (int i = 0; i < rcbtmc.Length; i++)
{
if (!string.IsNullOrEmpty(rcbtmc[i]))
{
RepositoryItemButtonEdit rc = new RepositoryItemButtonEdit();
rc.TextEditStyle = TextEditStyles.HideTextEditor;
rc.Buttons.Clear();
string[] btname = rcbtmc[i].Split(',');
for (int j = 0; j < btname.Length; j++)
{
if (!string.IsNullOrEmpty(btname[j]))
{
EditorButton bt1 = new EditorButton();
bt1.Caption = btname[j];
bt1.Kind = ButtonPredefines.Glyph;
rc.Buttons.Add(bt1);
}
}
rcbt[i] = rc;
rc.ButtonClick += Ljcx_buttonclick; // 绑定链接跳转事件
GridCX.RepositoryItems.Add(rc);
}
}
gdgv.CustomRowCellEdit += Gdgv_customrowcelledit; // 动态分配编辑器
}
}
gdgv.EndUpdate();
// 设计模式下自动生成帮助文档
if (pSFSJ)
{
string strhelp = "\r\n" + fgnmc + "\r\n" + new string('=', fgnmc.Length * 2) + "\r\n\r\n" +
"一、功能用途\r\n\r\n";
string dt1xm = "二、数据项目\r\n";
for (int c = 0; c < dt1.Columns.Count; c++)
{
string fn = dt1.Columns[c].ColumnName;
DataRow[] dr = dtzd.Select("tname='" + ft1 + "' and fname='" + fn + "'");
if (dr.Length > 0)
{
dt1xm += dr[0]["fmemo"].ToString() + "(" + dr[0]["fname"].ToString() + ")。\r\n";
}
}
strhelp += dt1xm + "\r\n三、注意事项\r\n";
strhelp += "\r\n四、操作方法(参见汇总查询功能操作方法)\r\n";
KcDb.DBexec("update x9_help_yy set mbhelp='" + strhelp + "' where ztbh='" + fgnbh + "'");
}
GridCX.Visible = true;
}
KcDb.DBclose();
}
catch (Exception ex)
{
loaderr = true;
MsgExShow("初始数据视图", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 保存窗体设置:位置、大小、行高、列宽等
/// </summary>
private void SaveFmSet()
{
try
{
if (!sfzr) return;
string fmset = $"{this.Top},{this.Left},{this.Width},{this.Height},{gdgv.RowHeight},{(int)this.WindowState}";
FmSave(fgnmc, fmset);
if (gdgv != null && gdgv.RowCount > 0)
{
fmset = gdgv.Columns[0].Width.ToString().Trim();
for (int g = 1; g < gdgv.Columns.Count; g++)
{
int cw = -1;
if (gdgv.Columns[g].Visible)
cw = gdgv.Columns[g].Width;
fmset += "," + cw.ToString();
}
FmSave(fgnmc + "表格", fmset);
}
}
catch (Exception ex)
{
MsgExShow("保存窗口参数", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// 文本字段按钮点击事件:打开文本编辑窗体
/// </summary>
private void Text_buttonclick(object sender, ButtonPressedEventArgs e)
{
var be = sender as ButtonEdit;
var fmrt = new FmTEXT();
Text_edit(fmrt, this, ref be, e.Button.Caption);
fmrt.Dispose();
}
/// <summary>
/// 网格视图键盘按下事件:支持Ctrl+加号/减号调整列宽,Ctrl+数字锁定列
/// </summary>
private void View_keydown(object sender, KeyEventArgs e)
{
// 设置最大或最小列宽
if (gdgv.RowCount > 0)
{
if ((e.KeyCode == Keys.Add) && (e.Modifiers == Keys.Control))
{
try
{
gdgv.FocusedColumn.Width = pMaxWt; // 设置为最大宽度
}
catch (Exception ex)
{
MsgExShow("设置最大列宽", ex.Message, ex.Source, ex.StackTrace);
return;
}
}
if ((e.KeyCode == Keys.Subtract) && (e.Modifiers == Keys.Control))
{
try
{
gdgv.FocusedColumn.Width = pMinWt; // 设置为最小宽度
}
catch (Exception ex)
{
MsgExShow("设置最小列宽", ex.Message, ex.Source, ex.StackTrace);
return;
}
}
}
// 锁定或取消锁定列(Ctrl+数字键)
try
{
if ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) && (e.Modifiers == Keys.Control))
{
int maxcol = (gdgv.VisibleColumns.Count - 1 < 10) ? gdgv.VisibleColumns.Count - 1 : 9;
for (int i = maxcol; i >= 0; i--)
{
gdgv.VisibleColumns[i].Fixed = FixedStyle.None; // 先取消所有锁定
}
if (e.KeyCode > Keys.D0)
{
int idx = Math.Min((int)e.KeyCode - 49, gdgv.VisibleColumns.Count - 2);
for (int i = 0; i <= idx; i++)
{
gdgv.VisibleColumns[i].Fixed = FixedStyle.Left; // 锁定前N列
}
}
}
}
catch (Exception ex)
{
MsgExShow("锁定或取消锁定列", ex.Message, ex.Source, ex.StackTrace);
}
}
/// <summary>
/// F4键事件:打开搜索链接(基于列Tag中定义的URL模板)
/// </summary>
private void View_keyf4(object sender, KeyEventArgs e)
{
try
{
if (e.KeyCode != Keys.F4)
return;
string[] ttag = gdgv.FocusedColumn.Tag.ToString().Split(',');
if (string.IsNullOrEmpty(ttag[1]))
return;
string ttext = gdgv.GetRowCellValue(gdgv.FocusedRowHandle, gdgv.FocusedColumn).ToString();
if (string.IsNullOrWhiteSpace(ttext))
return;
if (ttext.Length > 20)
ttext = ttext.Substring(0, 20);
string sstr = ttag[1]; // URL模板,如 "http://xxx?q={0}"
string searchstr = string.Format(sstr, System.Net.WebUtility.UrlDecode(ttext));
Process.Start(searchstr); // 打开浏览器
}
catch { }
}
/// <summary>
/// 超链接字段F4键事件:直接打开单元格中的URL
/// </summary>
private void View_keylink(object sender, KeyEventArgs e)
{
try
{
if (e.KeyCode != Keys.F4)
return;
string[] ttag = gdgv.FocusedColumn.Tag.ToString().Split(',');
if (ttag[0] != "hyperlinkedit")
return;
string ttext = gdgv.GetRowCellValue(gdgv.FocusedRowHandle, gdgv.FocusedColumn).ToString();
if (string.IsNullOrWhiteSpace(ttext))
return;
Process.Start(ttext); // 打开链接
}
catch { }
}
/// <summary>
/// 自定义单元格绘制事件:根据条件显示样式表设置单元格前景色/背景色
/// </summary>
private void View_tjxs(object sender, RowCellCustomDrawEventArgs e)
{
try
{
if (dttjxs == null || dttjxs.Rows.Count <= 0)
return;
for (int h = 0; h < dttjxs.Rows.Count; h++)
{
// 检查当前列是否匹配条件列或"all"(全部列)
if (dttjxs.Rows[h]["xsl"].ToString().ToLower() == e.Column.FieldName.ToLower() ||
dttjxs.Rows[h]["xsl"].ToString().ToLower() == "all")
{
bool bgfc = Convert.ToBoolean(dttjxs.Rows[h]["bgfc"]); // 是否改变前景色
bool bgbc = Convert.ToBoolean(dttjxs.Rows[h]["bgbc"]); // 是否改变背景色
string tjl = dttjxs.Rows[h]["tjl"].ToString(); // 条件字段名
int tjfx = Convert.ToInt32(dttjxs.Rows[h]["tjfx"]); // 条件期望值
int tjz = Convert.ToInt32(gdgv.GetRowCellValue(e.RowHandle, gdgv.Columns[tjl])); // 实际值
if (tjfx == tjz)
{
// 条件匹配,应用颜色
if (bgfc)
{
Color fc = Color.FromArgb(Convert.ToInt32(dttjxs.Rows[h]["fc"]));
e.Appearance.ForeColor = fc;
}
if (bgbc)
{
Color bc = Color.FromArgb(Convert.ToInt32(dttjxs.Rows[h]["bc"]));
e.Appearance.BackColor = bc;
}
}
}
}
}
catch (Exception ex)
{
MsgExShow("定制单元格外观", ex.Message, ex.Source, ex.StackTrace);
gdgv.CustomDrawCell -= View_tjxs; // 出错时移除事件,避免重复报错
}
}
}
}
四、窗体功能代码说明
汇总查询功能模型 (Uf10Cxhz) 说明
(一)概述
1.1 功能定位
Uf10Cxhz.cs 是ERP系统中的通用汇总查询模型,为系统提供一个统一的、可配置的数据查询、展示和输出平台。该模型通过参数化配置,能够适应不同的业务查询需求,实现"一次开发,多处使用"的设计理念。
1.2 核心特性
- ✅ 动态查询配置:基于数据字典和SQL模板的灵活查询
- ✅ 条件管理:用户可保存和重用查询条件
- ✅ 多格式打印:支持普通报表、卡片、标签等多种打印模板
- ✅ 智能链接:字段级功能跳转和数据关联
- ✅ 权限控制:细粒度的操作权限管理
- ✅ 界面定制:可保存的窗口布局和表格列宽设置
- ✅ 数据缓存:查询结果本地缓存提升性能
- ✅ 扩展性强:支持文件字段、超链接、条件样式等高级功能
(二)技术架构
2.1 技术栈
开发框架:Windows Forms + DevExpress 20.1+
数据库:支持SQL Server等(通过KcDb抽象层)
报表引擎:DevExpress XtraReports
数据绑定:DevExpress GridControl + GridView
2.2 项目结构
KcErp.Uf10Cxhz
├── 公共字段区 (dim public) # 功能参数和状态变量
├── 构造函数与事件绑定 # 初始化组件和事件
├── 工具栏功能模块 # 载入、打印、帮助等
├── 核心数据流程 # Dtzr() 方法
├── 打印处理模块 # DoPrintCx() 方法
├── 视图初始化 # Loadgv() 方法
├── 事件处理程序 # 键盘、鼠标、菜单事件
├── 资源管理 # 窗体销毁和清理
└── 辅助功能 # 工具方法
(三)核心功能详解
3.1 数据载入流程 (Dtzr方法)
3.1.1 流程步骤
1. 条件加载 → 2. 条件编辑 → 3. SQL生成 → 4. 数据获取
5. 缓存处理 → 6. 数据绑定 → 7. 视图初始化 → 8. 布局应用
3.1.2 条件管理机制
sql
-- 条件存储表结构
x9_gn_0zrtj:
- dyid: 唯一标识
- gnbh: 功能编号
- yhmc: 用户名
- tjxh: 条件序号
- tjmc: 条件名称
- tjjg: 条件结果值
- tjedit: 编辑器类型 (dateedit, textedit等)
- rxkz: 可选值限制
3.1.3 缓存策略
csharp
// 缓存文件命名规则
string qrname = pFilesQuery + "\\" + pDBmc + Hfwjm(功能名+条件值);
// 缓存文件:.xml (数据) + .xmlschema (结构)
// 有效期:无固定期限,通过sfcxcx参数控制是否重新查询
3.2 视图初始化 (Loadgv方法)
3.2.1 列属性配置
基于数据字典 x9_sjzd 动态配置:
- 字段类型:文本、数字、日期、文件、链接等
- 显示属性:标题、宽度、可见性、排序、过滤
- 编辑控制:只读/可编辑、编辑器类型、验证规则
3.2.2 特殊字段处理
| 字段类型 | 说明 | 事件绑定 |
|---|---|---|
| 文件字段 | 存储附件路径 | File_buttonclick |
| 链接字段 | 功能跳转 | Ljcx_buttonclick |
| 按钮文本 | 文本编辑按钮 | Text_buttonclick |
| 超链接 | 网页链接 | View_keylink (F4) |
| 搜索字段 | 带搜索模板 | View_keyf4 (F4) |
3.2.3 条件样式 (条件显示)
sql
-- 样式配置表 x9_gn_tjxs
-- 可配置:目标列、条件列、条件值、前景色、背景色
-- 示例:当状态=2时,金额列显示红色
3.3 打印系统 (DoPrintCx方法)
3.3.1 打印模板管理
模板来源:x9_gn_0dymb 表
模板类型:
- 普通报表:多行数据
- 卡片打印:单行详细
- 标签打印:单行紧凑格式
特殊模板:"直接打印" → 使用GridView原生打印
3.3.2 数据源结构
csharp
DataSet ds = new DataSet("dataset1");
ds.Tables.Add("t1"); // 表头:标题+条件值(一行)
ds.Tables.Add("t2"); // 数据:查询结果(多行)
3.3.3 文件字段处理
打印前自动下载文件字段到本地缓存目录,将数据库路径转换为本地路径供报表使用。
3.4 链接跳转机制
3.4.1 链接配置
csharp
// 在数据字典中配置链接字段
ftcxljzd = "链接字段名";
// 字段值格式:"功能名称1,功能名称2"
3.4.2 跳转逻辑
- 条件传递:将当前查询条件和选中行数据传递给目标功能
- 权限验证:检查用户是否有目标功能权限
- 单据查询特殊处理:传递相关oid(单据号)列表
- 条件保存:更新目标功能的用户条件表
(四)权限控制系统
4.1 权限字符串格式
csharp
fxz = "01101"; // 5位权限字符串
位置含义:[0]预留, [1]打印, [2]编辑, [3]文件, [4]导出
值为"1"表示有权限,"0"表示无权限
4.2 权限影响的功能
- xzdy (打印权限):控制打印和预览按钮
- xzwj (文件权限):控制文件字段的编辑/下载
- xzdc (导出权限):控制XML导出功能(预留)
- xzbj (编辑权限):控制数据编辑(本模块主要为查询)
- xzck (查看权限):基础查看权限
(五)用户界面功能
5.1 工具栏功能
| 按钮 | 功能 | 启用条件 |
|---|---|---|
| 载入 | 重新查询数据 | 始终启用 |
| 打印预览 | 预览报表 | 已载入数据且有打印权限 |
| 直接打印 | 立即打印 | 已载入数据且有打印权限 |
| 帮助 | 打开帮助文档 | 始终启用 |
| 退出 | 关闭窗口 | 始终启用 |
5.2 右键菜单
- 自动配置列宽:根据内容自动调整列宽
- 手动配置列宽:保持当前列宽设置
5.3 快捷键
| 快捷键 | 功能 |
|---|---|
| Ctrl + + | 当前列设为最大宽度 |
| Ctrl + - | 当前列设为最小宽度 |
| Ctrl + 1-9 | 锁定前N列(左固定) |
| Ctrl + 0 | 取消所有列锁定 |
| F4 (超链接字段) | 打开单元格中的URL |
| F4 (搜索字段) | 使用模板打开搜索页面 |
5.4 布局保存
csharp
// 窗口布局:Top,Left,Width,Height,RowHeight,WindowState
// 列宽布局:各列宽度(-1表示隐藏)
// 保存位置:配置文件或数据库
(六)数据流与状态管理
6.1 主要状态变量
csharp
bool sfzr; // 数据是否已载入(核心状态)
bool loading; // 是否正在加载
bool loaderr; // 加载过程是否出错
bool sfgv; // 是否使用GridView视图
bool fh; // 是否正在返回关闭
6.2 数据生命周期
窗体加载 → 权限检查 → 模板加载 → 条件初始化
↓
用户交互 → 条件修改 → 数据查询 → 缓存写入
↓
数据显示 → 用户操作 → 打印/跳转 → 布局保存
↓
窗体关闭 → 资源释放 → 状态清理
(七)配置与扩展
7.1 功能配置表
sql
-- 主要配置表
x9_gn_0zrtj -- 用户查询条件
x9_sjzd -- 数据字典(字段属性)
x9_gn_0dymb -- 打印模板定义
x9_gn_tjxs -- 条件显示样式
7.2 扩展点
- 新的字段类型:在数据字典中增加新的ctag类型,并相应的事件处理
- 新的打印格式:在x9_gn_0dymb中新增模板,在DoPrintCx中添加相应逻辑
- 新的链接类型:扩展Ljcx_buttonclick方法,支持新的gnly类型
- 条件样式扩展:在x9_gn_tjxs中增加新的显示规则
7.3 性能优化建议
- 分页加载:对于大数据量,可考虑实现分页查询
- 异步加载:将数据查询和界面更新分离
- 缓存清理:定期清理过期的查询缓存文件
- 索引优化:确保查询SQL的相关字段有适当索引
(八)使用示例
8.1 创建新的查询功能
sql
-- 1. 在功能表中注册新功能
INSERT INTO x9_gn (gnbh, gnmc, gnly, ...)
VALUES ('CX001', '销售汇总查询', '汇总查询', ...);
-- 2. 定义数据字典
INSERT INTO x9_sjzd (tname, fname, fmemo, ctag, ...)
VALUES
('销售表', '客户名称', '客户全称', 'textread', ...),
('销售表', '销售金额', '含税金额', 'numeric', ...),
('销售表', '查看明细', '链接到明细查询', 'buttontextread', ...);
-- 3. 定义查询SQL模板
UPDATE x9_gn SET ftsql = 'SELECT * FROM 销售表 WHERE 1=1 {条件替换}'
WHERE gnbh = 'CX001';
-- 4. 定义打印模板(可选)
INSERT INTO x9_gn_0dymb (gnbh, mbmc, ...)
VALUES ('CX001', '销售汇总报表', ...);
8.2 常用操作流程
- 首次使用:进入功能 → 设置查询条件 → 执行查询 → 保存条件
- 日常查询:选择保存的条件 → 执行查询 → 查看/打印数据
- 数据分析:使用列筛选 → 排序 → 条件样式突出显示 → 导出
- 关联操作:点击链接字段 → 跳转到关联功能 → 查看详细信息
(九)故障排除
9.1 常见问题
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法连接数据库 | 连接字符串错误/服务器不可用 | 检查主窗口连接状态 |
| 查询无数据 | SQL模板错误/条件不匹配 | 检查SQL日志,验证条件值 |
| 打印预览空白 | 模板设计问题/数据源不匹配 | 检查报表模板的数据绑定 |
| 链接跳转失败 | 权限不足/目标功能未定义 | 检查用户权限和目标功能配置 |
| 界面布局混乱 | 配置文件损坏 | 删除布局配置文件重新设置 |
9.2 日志与调试
- 错误信息:通过MsgExShow显示详细错误(消息、源、堆栈)
- SQL跟踪:pSFSJ模式下记录执行的SQL语句
- 缓存调试:检查pFilesQuery目录下的XML文件
全文总结
该文档详尽阐述了看潮企业管理软件(KcErp)中汇总查询功能模型(Uf10Cxhz)的技术架构与实现细节。作为ERP系统的通用查询平台,该模块采用C#与DevExpress WinForms控件库构建,通过参数化配置实现"一次开发,多处使用"的设计理念。
技术架构方面,模块集成RibbonControl功能区、GridControl数据网格与XtraReports报表引擎,提供美观且功能丰富的用户界面。核心功能包括:基于数据字典(x9_sjzd)的动态列配置与SQL生成机制;用户查询条件的保存与重用(x9_gn_0zrtj表管理);支持普通报表、卡片、标签等多格式的打印系统;字段级功能跳转与单据关联查询;以及基于XML文件的查询结果缓存机制。
系统实现了完善的权限控制体系,通过5位权限字符串控制打印、导出、文件操作等行为。用户体验方面,提供快捷键操作(Ctrl+数字锁定列、F4打开链接)、右键菜单(自动/手动配置列宽)、条件样式显示(根据数值改变单元格颜色)等交互特性。
该模块设计注重性能与扩展性,支持大数据量查询、异步加载、多视图切换(网格/卡片),并通过配置化方式适应不同业务场景,为ERP系统提供了统一的查询与报表输出解决方案,适用于库存汇总、销售统计、财务报表等业务场景。