摘要:本文围绕《看潮企业管理软件》主窗口设计展开,提出“角色驱动、任务分区、权限过滤”三原则,用Ribbon+左导航+右工作区布局,动态加载图标与菜单,集成任务流、皮肤、参数持久化,兼顾高效操作与可扩展性,为ERP界面现代化提供完整范例。

关键词:ERP主窗口、角色驱动、Ribbon界面、动态权限、任务流、DevExpress、可扩展性、用户体验

人工智能助手:DeepSeek、Kimi


五、窗体功能代码

功能代码是开发过程中编写的窗口初始化代码和事件代码、窗口过程和函数等。在VS2022中,基本的程序框架也是自动生成的。

下面给出本项目的第一个复杂代码,主窗口功能代码,部分内容需要以后的内容加以说明,可以先行阅读代码,来了解做为主窗口需要完成的处理。

/*
 * 文件:FmMain.cs
 * 功能:看潮ERP主窗口
 * 说明:该窗口为软件运行的主窗口
 */
using DevExpress.Utils;
using DevExpress.Utils.Menu;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Ribbon;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraLayout;
using DevExpress.XtraTab;
using System;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;
using static KcErp.KcDb;
using static KcErp.KcEditgd;
using static KcErp.KcMain;

namespace KcErp
{
    /// <summary>
    /// ERP系统主窗口类
    /// 继承自DevExpress的RibbonForm,提供带功能区的高级窗口界面
    /// 这是整个ERP系统的核心容器和总控制台
    /// </summary>
    public partial class FmMain : DevExpress.XtraBars.Ribbon.RibbonForm
    {
        #region 窗口变量
        // 以下是主窗口使用的核心变量,用于存储状态、数据和UI组件引用
        public static GridView rwgv = new GridView();     // “我的任务”表格视图,用于显示待办任务列表
        public static GridView ztgv = new GridView();     // “系统状态”表格视图,用于监控系统状态
        public string cslj;                               // 系统配置和文件存储的根路径(如:C:\ProgramData\KcErp\FormCs\)
        public DataTable dtgntp;                          // 功能模块图标数据表,存储各功能模块对应的图标信息
        public string fmset;                              // 窗口设置信息字符串,用于序列化/反序列化窗口状态
        public ImageCollection gnimage = new ImageCollection(); // 功能图标集合,存储所有功能模块的图标
        public LayoutControl jclc = new LayoutControl();  // “基础资料”面板的布局控件,用于动态生成功能按钮布局
        public int pczts;                                 // 程序状态标志,用于跟踪应用程序的运行时状态
        public bool pquit = false;                        // 退出标志,为true时表示正在退出程序,防止重复清理操作
        public RepositoryItemButtonEdit[] rcbt;           // 任务列表中操作按钮的编辑器控件数组,每个任务可能有不同的操作按钮
        public string[] rcbtmc;                           // 操作按钮名称数组,与rcbt数组对应,存储按钮的显示文本
        public RepositoryItemTextEdit rctt = new RepositoryItemTextEdit(); // 默认文本编辑器,用于任务列表中没有自定义按钮的单元格
        public string sqmk = "";                          // 授权模块字符串,存储用户有权限访问的模块列表(以逗号分隔)
        public LayoutControl xxlc = new LayoutControl();  // “信息查询”面板的布局控件
        public LayoutControl ywlc = new LayoutControl();  // “业务处理”面板的布局控件
        #endregion 窗口变量
        
        public bool gnyx = false;                         // 功能运行状态标志,为true时表示某个功能正在运行,防止重复激活

        /// <summary>
        /// 主窗口构造函数
        /// 初始化窗口组件并绑定所有事件处理器
        /// 这是窗口生命周期的起点
        /// </summary>
        public FmMain()
        {
            // 初始化窗体组件(由设计器生成的代码)
            InitializeComponent();
            
            // 绑定Ribbon功能区按钮点击事件
            // 每个按钮点击都会触发相应的业务功能
            this.BarBQXX.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarBQXX_ItemClick);
            this.BarGNLB.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarGNLB_ItemClick);
            this.BarFLML.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarFLML_ItemClick);
            this.BarCXSR.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarCXSR_ItemClick);
            this.BarGLSR.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarGLSR_ItemClick);
            this.BarDJSR.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarDJSR_ItemClick);
            this.BarYWCL.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarYWCL_ItemClick);
            this.BarDJSP.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarDJSP_ItemClick);
            this.BarDJCX.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarDJCX_ItemClick);
            this.BarHZCX.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarHZCX_ItemClick);
            this.Barexit.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarEXIT_ItemClick);
            this.BarHELP.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarHELP_ItemClick);
            this.Barhelpsj.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarHELPSJ_ItemClick);
            this.BarExitsj.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarExitSj_ItemClick);
            this.BarYHXX.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarYHXX_ItemClick);
            this.BarSKIN.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarSKIN_ItemClick);
            this.BarSJLJ.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarSJLJ_ItemClick);
            this.BarWjxz.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarWjxz_ItemClick);
            this.BarYHMM.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarYHMM_ItemClick);
            this.BarZTLJ.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.BarZTLJ_ItemClick);
            
            // 绑定BarEditItem值变更事件(这些是功能区中的编辑控件)
            this.BarDqpt.EditValueChanged += new System.EventHandler(this.Bardqpt_EditValueChanged); // 打印机选择变更
            this.Tsywrq.EditValueChanged += new System.EventHandler(this.TsYwrq_EditValueChanged);   // 业务日期变更
            
            // 绑定普通按钮点击事件
            this.Btrwmw.Click += new System.EventHandler(this.Btrwmw_Click); // 刷新任务列表按钮
            
            // 绑定窗体生命周期事件
            this.Activated += new System.EventHandler(this.Form_Activated);           // 窗体激活时触发
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form_FormClosing); // 窗体关闭时触发
            this.Load += new System.EventHandler(this.Form_Load);                     // 窗体加载时触发
        }

        /// <summary>
        /// 创建文本文件的通用工具方法
        /// 主要用于生成日志文件、配置文件等
        /// </summary>
        /// <param name="filename">要创建的文件完整路径</param>
        /// <param name="texttoadd">要写入文件的文本内容</param>
        public static void CreateTextFile(string filename, string texttoadd)
        {
            // 使用UTF-8编码创建或覆盖文件
            StreamWriter swfromfile = new StreamWriter(filename, false, System.Text.Encoding.UTF8);
            swfromfile.Write(texttoadd); // 写入文本内容
            swfromfile.Flush();          // 清空缓冲区,确保数据写入磁盘
            swfromfile.Close();          // 关闭文件流
        }

        /// <summary>
        /// 动态配置网格视图列的核心方法
        /// 根据数据字典(x9_sjzd表)中的定义,为网格列创建不同类型的编辑器
        /// 支持按钮编辑器、复选框、日期选择器、文本编辑器等多种控件类型
        /// </summary>
        /// <param name="gd">网格控件引用</param>
        /// <param name="gv">网格视图引用</param>
        /// <param name="dtzd">数据字典DataTable,包含列定义信息</param>
        public static void Gdlomyrw(ref GridControl gd, ref GridView gv, ref DataTable dtzd)
        {
            try
            {
                // 定义列配置变量
                string tedit;        // 编辑控件类型:buttonedit/checkedit/dateedit/textread等
                string tfname;       // 数据库字段名
                string tftype;       // 字段数据类型
                string tfmemo;       // 字段说明(显示为列标题)
                string tsrlx;        // 输入类型
                string tformattype;  // 格式类型(如DateTime、Numeric)
                string tformatstr;   // 格式字符串(如"yyyy-MM-dd")
                int alignment;       // 对齐方式(0:左对齐, 1:居中, 2:右对齐)
                DataRow[] dr = null; // 存储查询到的列配置
                int cols;            // 网格列数
                
                cols = gv.Columns.Count;
                
                // 遍历网格的所有列,为每列配置相应的编辑器
                for (int i = 0; i <= cols - 1; i++)
                {
                    // 在数据字典中查找当前列的配置
                    dr = dtzd.Select("fname='" + gv.Columns[i].FieldName + "'");
                    string gcname = gv.Columns[i].Name;
                    
                    // 如果数据字典中没有该列的配置
                    if (dr.Length <= 0)
                    {
                        // 创建默认的文本编辑器(只读)
                        RepositoryItemTextEdit rc = new RepositoryItemTextEdit();
                        rc.Appearance.TextOptions.WordWrap = WordWrap.Wrap; // 允许文本换行
                        gd.RepositoryItems.Add(rc);                         // 添加到网格的编辑器集合
                        gv.Columns[i].ColumnEdit = rc;                     // 绑定到当前列
                        gv.Columns[i].OptionsColumn.AllowSort = DefaultBoolean.False; // 禁用排序
                        gv.Columns[i].OptionsColumn.AllowMove = false;     // 禁用列移动
                        gv.Columns[i].OptionsFilter.AllowFilter = false;   // 禁用筛选
                        gv.Columns[i].OptionsColumn.ReadOnly = true;       // 设置为只读
                    }
                    else
                    {
                        // 从数据字典中读取列配置
                        tfmemo = dr[0]["fmemo"].ToString();
                        tedit = dr[0]["edit"].ToString();
                        tfname = dr[0]["fname"].ToString();
                        tftype = dr[0]["ftype"].ToString();
                        tsrlx = dr[0]["srlx"].ToString();
                        tformattype = dr[0]["formattype"].ToString();
                        tformatstr = dr[0]["formatstr"].ToString();
                        alignment = Convert.ToInt32(dr[0]["alignment"]);
                        
                        // 根据编辑类型创建不同的编辑器控件
                        switch (tedit)
                        {
                            case "buttonedit": // 按钮编辑器(通常用于打开选择对话框)
                                {
                                    RepositoryItemButtonEdit rc = new RepositoryItemButtonEdit
                                    {
                                        TextEditStyle = TextEditStyles.Standard, // 标准文本编辑样式
                                        MaxLength = 0 // 不限制输入长度
                                    };
                                    
                                    // 如果有格式定义,设置显示格式
                                    if (tformattype != "" && tformatstr != "")
                                    {
                                        rc.DisplayFormat.FormatType = Tf(tformattype); // 显示格式类型
                                        rc.DisplayFormat.FormatString = tformatstr;    // 显示格式字符串
                                        rc.EditFormat.FormatType = Tf(tformattype);    // 编辑格式类型
                                        rc.EditFormat.FormatString = tformatstr;       // 编辑格式字符串
                                    }
                                    
                                    // 如果是选择类型,禁用文本编辑
                                    rc.TextEditStyle = (tformatstr.ToLower() == "select" ? 
                                        TextEditStyles.DisableTextEditor : TextEditStyles.Standard);
                                    
                                    gd.RepositoryItems.Add(rc);
                                    gv.Columns[i].ColumnEdit = rc;
                                    break;
                                }
                            case "checkedit":   // 复选框编辑器(可编辑)
                            case "checkread":   // 复选框编辑器(只读)
                                {
                                    RepositoryItemCheckEdit rc = new RepositoryItemCheckEdit();
                                    gd.RepositoryItems.Add(rc);
                                    gv.Columns[i].ColumnEdit = rc;
                                    break;
                                }
                            case "dateedit":    // 日期选择编辑器
                                {
                                    RepositoryItemDateEdit rc = new RepositoryItemDateEdit();
                                    // 设置日期格式
                                    if (tformattype != "" && tformatstr != "")
                                    {
                                        rc.DisplayFormat.FormatType = Tf(tformattype);
                                        rc.DisplayFormat.FormatString = tformatstr;
                                        rc.EditFormat.FormatType = Tf(tformattype);
                                        rc.EditFormat.FormatString = tformatstr;
                                    }
                                    gd.RepositoryItems.Add(rc);
                                    gv.Columns[i].ColumnEdit = rc;
                                    gv.Columns[i].OptionsColumn.AllowEdit = false; // 禁用编辑
                                    break;
                                }
                            default:            // 默认文本编辑器("textread"等)
                                {
                                    RepositoryItemTextEdit rc = new RepositoryItemTextEdit();
                                    rc.Appearance.TextOptions.WordWrap = WordWrap.Wrap;
                                    // 设置文本格式
                                    if (tformattype != "" && tformatstr != "")
                                    {
                                        rc.DisplayFormat.FormatType = Tf(tformattype);
                                        rc.DisplayFormat.FormatString = tformatstr;
                                        rc.EditFormat.FormatType = Tf(tformattype);
                                        rc.EditFormat.FormatString = tformatstr;
                                    }
                                    gd.RepositoryItems.Add(rc);
                                    gv.Columns[i].ColumnEdit = rc;
                                    break;
                                }
                        }
                        
                        // 设置列的对齐方式
                        Setag(ref gv, i, alignment);
                        // 设置列标题
                        gv.Columns[i].Caption = tfmemo;
                        // 设置列属性
                        gv.Columns[i].OptionsColumn.AllowSort = DefaultBoolean.False;
                        gv.Columns[i].OptionsColumn.AllowMove = true;
                        gv.Columns[i].OptionsFilter.AllowFilter = false;
                        // 在Tag中存储编辑类型,供后续使用
                        gv.Columns[i].Tag = tedit;
                    }
                    
                    // 设置列标题的样式
                    gv.Columns[i].AppearanceHeader.Options.UseTextOptions = true;
                    gv.Columns[i].AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center; // 水平居中
                    gv.Columns[i].AppearanceHeader.TextOptions.VAlignment = VertAlignment.Center; // 垂直居中
                    gv.Columns[i].AppearanceHeader.TextOptions.WordWrap = WordWrap.Wrap;          // 允许换行
                }
            }
            catch (Exception ex)
            {
                // 异常处理:显示详细的错误信息
                MsgExShow("初始我的任务表格视图", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 重新登录方法
        /// 保存当前窗口参数后重启应用程序,用于切换账套或重新连接后恢复工作环境
        /// </summary>
        public void ReLogin()
        {
            try
            {
                // 如果不是"否"模式(表示需要保存窗口参数)
                if (pFMSD == "否")
                {
                    if (pDSFM != null)
                    {
                        if (pDSFM.Tables.Count > 0)
                        {
                            try
                            {
                                // 将窗口参数保存到XML文件(按数据库名和屏幕分辨率命名)
                                pDSFM.WriteXml(cslj + pDBmc + "_" + myscreen + ".xml");
                                pDSFM.AcceptChanges(); // 接受更改,标记为未修改状态
                            }
                            catch (Exception ex)
                            {
                                MsgExShow("提交窗口参数", ex.Message, ex.Source, ex.StackTrace);
                            }
                        }
                    }
                }
                Application.Restart(); // 重启整个应用程序
            }
            catch (Exception)
            {
                // 静默处理异常,避免重启失败时造成程序崩溃
            }
        }

        /// <summary>
        /// 版权信息按钮点击事件
        /// 显示关于窗口,展示软件版本、版权等信息
        /// </summary>
        private void BarBQXX_ItemClick(object sender, ItemClickEventArgs e)
        {
            FmAbout xf = new FmAbout();     // 创建关于窗口实例
            xf.LZTMC.Text = pZTMC;          // 设置账套名称
            xf.ShowDialog(this);            // 以模态方式显示关于窗口
            xf.Dispose();                   // 释放窗口资源
        }

        /// <summary>
        /// 查询输入功能定义按钮点击事件
        /// 打开查询输入功能的定义界面
        /// </summary>
        private void BarCXSR_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("查询输入"); // 调用通用方法打开功能定义窗口
        }

        /// <summary>
        /// 单据查询功能定义按钮点击事件
        /// 打开单据查询功能的定义界面
        /// </summary>
        private void BarDJCX_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("单据查询");
        }

        /// <summary>
        /// 单据审批功能定义按钮点击事件
        /// 打开单据审批功能的定义界面
        /// </summary>
        private void BarDJSP_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("单据审批");
        }

        /// <summary>
        /// 单据输入功能定义按钮点击事件
        /// 打开单据输入功能的定义界面
        /// </summary>
        private void BarDJSR_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("单据输入");
        }

        /// <summary>
        /// 当前打印机选择变更事件
        /// 当用户在功能区更改打印机时更新全局打印机设置
        /// </summary>
        private void Bardqpt_EditValueChanged(object sender, EventArgs e)
        {
            try
            {
                pPrinterName = BarDqpt.EditValue.ToString(); // 更新全局打印机名称变量
            }
            catch (Exception)
            {
                // 静默处理异常,避免因打印机设置问题导致程序崩溃
            }
        }

        /// <summary>
        /// 退出按钮点击事件(账套模式)
        /// 关闭主窗口,触发FormClosing事件保存设置
        /// </summary>
        private void BarEXIT_ItemClick(object sender, ItemClickEventArgs e)
        {
            this.Close(); // 触发FormClosing事件,在事件中保存设置并清理资源
        }

        /// <summary>
        /// 退出按钮点击事件(设计模式)
        /// 在设计模式下退出时显式保存窗口设置
        /// </summary>
        private void BarExitSj_ItemClick(object sender, ItemClickEventArgs e)
        {
            SaveFmSet(); // 保存窗口设置
            this.Close(); // 关闭窗口
        }

        /// <summary>
        /// 分类目录功能定义按钮点击事件
        /// 打开分类目录功能的定义界面
        /// </summary>
        private void BarFLML_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("分类目录");
        }

        /// <summary>
        /// 关联输入功能定义按钮点击事件
        /// 打开关联输入功能的定义界面
        /// </summary>
        private void BarGLSR_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("关联输入");
        }

        /// <summary>
        /// 功能列表定义按钮点击事件
        /// 打开功能列表管理界面,用于管理系统所有功能模块
        /// </summary>
        private void BarGNLB_ItemClick(object sender, ItemClickEventArgs e)
        {
            try
            {
                // 检查功能列表定义窗口是否已经打开(避免重复打开)
                foreach (Form opfm in Application.OpenForms)
                {
                    if (opfm.Name == "gn01_flml")
                    {
                        if (opfm.Text == "功能列表定义")
                        {
                            // 如果已打开,则激活并前置该窗口
                            opfm.WindowState = FormWindowState.Normal;
                            opfm.Activate();
                            return; // 直接返回,不再创建新窗口
                        }
                    }
                }
                
                // 创建新的功能列表定义窗口
                Uf01Flml gnform = new Uf01Flml
                {
                    Text = "功能列表定义",       // 窗口标题
                    fgnbh = "9982",            // 功能编号
                    fgnmc = "功能列表定义",     // 功能名称
                    ftlist = "gnbh,sj,bj,jc,gnmc,gnly,gnlb,ssmk,t1,t2,zdbb,sfyc,sfqy,sfql,sfsd", // 显示字段列表
                    ftbm = "gnbh",             // 主键字段
                    ftsj = "sj",               // 时间字段
                    ftbj = "bj",               // 标记字段
                    ftmc = "gnmc",             // 名称字段
                    ftone = "",                // 单选框字段(空表示不使用)
                    ftml = "gnbh,gnmc,gnly,gnlb,ssmk,t1,t2,zdbb,sfyc,sfqy,sfql", // 模板字段
                    ftjc = "jc",               // 简称字段
                    ftwhere = "1=1",           // 查询条件(1=1表示查询所有)
                    ftorder = "gnbh",          // 排序字段
                    ftqy = "sfsd",             // 启用字段
                    ftfz = true,               // 是否允许复制
                    ft1 = "x9_gn",             // 主表名
                    ftbb = "",                 // 版本号(空表示无版本控制)
                    fxz = "11111111"           // 权限控制字符串(8位二进制,每位代表一种操作权限)
                };
                gnform.Show(); // 以非模态方式显示窗口
            }
            catch (Exception ex)
            {
                MsgExShow("执行功能列表定义", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 帮助按钮点击事件(账套模式)
        /// 打开帮助文档或帮助系统
        /// </summary>
        private void BarHELP_ItemClick(object sender, ItemClickEventArgs e)
        {
            RunHelpyy(this, pZTMC, pSFSJ); // 调用帮助系统
        }

        /// <summary>
        /// 帮助按钮点击事件(设计模式)
        /// 打开设计模式的帮助文档
        /// </summary>
        private void BarHELPSJ_ItemClick(object sender, ItemClickEventArgs e)
        {
            RunHelpsj(this, pZTMC); // 调用设计模式帮助
        }

        /// <summary>
        /// 汇总查询功能定义按钮点击事件
        /// 打开汇总查询功能的定义界面
        /// </summary>
        private void BarHZCX_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("汇总查询");
        }

        /// <summary>
        /// 数据库重新连接按钮点击事件
        /// 当数据库连接异常断开时,尝试重新连接数据库
        /// </summary>
        private void BarSJLJ_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            try
            {
                KcDb.SFlj = KcDb.DBLJ(); // 重新获取数据库连接字符串
            }
            catch (Exception ex)
            {
                MsgExShow("重新连接本地数据库", ex.Message, ex.Source, ex.StackTrace);
            }
            // 显示当前数据库连接状态
            MsgXxShow("数据库连接目前处理于[" + Gethydbzt() + "]状态");
        }

        /// <summary>
        /// 设置皮肤按钮点击事件
        /// 打开皮肤选择窗口,允许用户更改界面主题
        /// </summary>
        private void BarSKIN_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            FmSKIN skfm = new FmSKIN(); // 创建皮肤设置窗口
            skfm.ShowDialog();          // 以模态方式显示
            skfm.Dispose();             // 释放窗口资源
        }

        /// <summary>
        /// 文件下载按钮点击事件
        /// 打开文件下载管理界面(需要系统管理员权限)
        /// </summary>
        private void BarWjxz_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            // 权限检查:只有系统管理员可以访问此功能
            if (!pYHJS.Contains("系统管理员"))
            {
                MsgXxShow("该功能需要系统管理员权限!");
                return; // 无权限,直接返回
            }
            
            FmWjxz fmwj = new FmWjxz(); // 创建文件下载窗口
            fmwj.Show();                // 以非模态方式显示
        }

        /// <summary>
        /// 用户密码修改按钮点击事件
        /// 打开密码修改窗口,允许当前用户修改登录密码
        /// </summary>
        private void BarYHMM_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            FmYHMM fmm = new FmYHMM(); // 创建密码修改窗口
            fmm.ShowDialog(this);      // 以模态方式显示,this作为父窗口
        }

        /// <summary>
        /// 用户信息查看按钮点击事件
        /// 打开当前用户信息查看窗口
        /// </summary>
        private void BarYHXX_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            try
            {
                FmYhxx fyhxx = new FmYhxx(); // 创建用户信息窗口
                fyhxx.ShowDialog();          // 以模态方式显示
            }
            catch (Exception ex)
            {
                MsgExShow("重新连接本地数据库", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 业务处理功能定义按钮点击事件
        /// 打开业务处理功能的定义界面
        /// </summary>
        private void BarYWCL_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            RunGndy("业务处理");
        }

        /// <summary>
        /// 重新启动按钮点击事件
        /// 保存当前状态后重新启动应用程序(用于切换账套等场景)
        /// </summary>
        private void BarZTLJ_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            ReLogin(); // 调用重新登录方法
        }

        /// <summary>
        /// 刷新任务列表按钮点击事件
        /// 手动刷新右侧的"我的任务"列表,获取最新的待办任务
        /// </summary>
        private void Btrwmw_Click(object sender, EventArgs e)
        {
            Reloadrw(GridRW, rwgv); // 重新加载任务数据
        }

        /// <summary>
        /// 自动配置列宽菜单项点击事件(从右键菜单调用)
        /// 根据当前网格宽度自动调整所有可见列的宽度
        /// </summary>
        private void Dxmenuclick()
        {
            Gvoptionwithmin(ref rwgv, GridRW.Width); // 调用自动调整列宽的方法
        }

        /// <summary>
        /// 手动配置列宽菜单项点击事件(从右键菜单调用)
        /// 保存当前列宽设置为默认配置
        /// </summary>
        private void Dxsdclick()
        {
            Gvsdoption(ref rwgv); // 调用保存列宽配置的方法
        }

        /// <summary>
        /// 窗口激活事件
        /// 当窗口从后台切换到前台时触发,用于刷新任务列表
        /// </summary>
        private void Form_Activated(object sender, EventArgs e)
        {
            if (pquit) return; // 如果正在退出程序,直接返回
            
            if (gnyx) // 如果功能正在运行
            {
                gnyx = false; // 重置标志
                return;
            }
            
            Reloadrw(GridRW, rwgv); // 刷新任务列表,确保显示最新任务
            
            if (this.WindowState != FormWindowState.Normal) return; // 如果窗口不是正常状态,返回
            
            this.Focus(); // 获取焦点
        }

        /// <summary>
        /// 窗口关闭事件
        /// 在窗口关闭前保存所有设置并清理资源
        /// </summary>
        private void Form_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 保存窗口参数到XML文件
            if (pFMSD == "否")
            {
                if (pDSFM != null)
                {
                    try
                    {
                        pDSFM.WriteXml(cslj + pDBmc + "_" + myscreen + ".xml");
                        pDSFM.AcceptChanges(); // 标记为已保存
                    }
                    catch (Exception ex)
                    {
                        MsgExShow("提交窗口参数", ex.Message, ex.Source, ex.StackTrace);
                    }
                }
            }
            
            // 关闭数据库连接
            try
            {
                pquit = true; // 设置退出标志
                KcDb.Dispose(); // 释放数据库资源
            }
            catch (Exception ex)
            {
                MsgExShow("关闭数据连接", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 窗口加载事件 - 系统初始化入口
        /// 在窗口显示前执行所有初始化操作
        /// 执行顺序:环境检查 → 数据库连接 → 权限加载 → 界面构建
        /// </summary>
        private void Form_Load(object sender, EventArgs e)
        {
            try
            {
                this.Visible = false; // 先隐藏窗口,避免初始化过程闪烁
                
                // 1. 获取屏幕信息和设置窗口
                pBJMC = System.Environment.MachineName; // 计算机名
                pFMWX = Screen.PrimaryScreen.WorkingArea.Width; // 主屏幕工作区宽度
                pFMWY = Screen.PrimaryScreen.WorkingArea.Height; // 主屏幕工作区高度
                SetDg(this, 1680, 700, true); // 设置窗口默认大小和位置(1680x700,居中显示)
                
                // 计算屏幕缩放比例(基于1920x1080基准分辨率)
                double bzwt = 1920.0;
                double pmwt = Convert.ToDouble(pFMWX);
                pFMBL = pmwt / bzwt; // 缩放比例,用于自适应不同分辨率
                
                // 设置分割器的默认位置
                Sp1.SplitterPosition = 298;
                
                // 生成屏幕分辨率标识字符串(如:1920_1080)
                myscreen = Screen.PrimaryScreen.WorkingArea.Width.ToString().Trim() + "_" + 
                          Screen.PrimaryScreen.WorkingArea.Height.ToString().Trim();
                
                // 2. 设置状态栏日期显示
                tsRQ.Caption = KcTool.GetYLDate(DateTime.Now.Date); // 格式化为中文日期
                
                // 3. 获取PC唯一标识
                pPCBH = GetId();
                
                // 4. 设置Ribbon标题
                RibbonControl.ApplicationDocumentCaption = "看潮企业管理软件";
                RibbonControl.ApplicationCaption = "看潮企业管理软件";
                
                // 5. 初始化配置目录
                cslj = pAppPath + "FormCs"; // 配置存储路径
                if (!System.IO.Directory.Exists(cslj))
                {
                    System.IO.Directory.CreateDirectory(cslj);
                }
                // 创建图片存储子目录(分为三类图标)
                if (!System.IO.Directory.Exists(cslj + "\\image1"))
                {
                    System.IO.Directory.CreateDirectory(cslj + "\\image1");
                }
                if (!System.IO.Directory.Exists(cslj + "\\image2"))
                {
                    System.IO.Directory.CreateDirectory(cslj + "\\image2");
                }
                if (!System.IO.Directory.Exists(cslj + "\\image3"))
                {
                    System.IO.Directory.CreateDirectory(cslj + "\\image3");
                }
                
                // 6. 初始化文档目录
                pDoc = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                if (!System.IO.Directory.Exists(pDataRoot))
                {
                    System.IO.Directory.CreateDirectory(pDataRoot);
                }
                
                cslj = cslj + "\\"; // 确保路径以反斜杠结尾
            }
            catch (Exception ex)
            {
                MsgExShow("初始应用环境", ex.Message, ex.Source, ex.StackTrace);
            }
            
            // 7. 加载主程序
            try
            {
                LoadForm(); // 核心初始化方法
            }
            catch (Exception ex)
            {
                MsgExShow("加载应用程序", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 网格自定义行单元格编辑器事件
        /// 根据单元格值动态设置单元格的编辑器类型
        /// 主要用于任务列表中的"执行"按钮列
        /// </summary>
        private void Gdgv_Customrowcelledit(object sender, DevExpress.XtraGrid.Views.Grid.CustomRowCellEditEventArgs e)
        {
            try
            {
                // 只处理"rwexec"列(执行操作列)
                if (e.Column.FieldName != "rwexec")
                {
                    return;
                }
                
                // 获取单元格值
                string cellValue = e.CellValue?.ToString().Trim() ?? "";
                
                if (cellValue == "")
                {
                    // 如果值为空,使用默认文本编辑器
                    e.RepositoryItem = rctt;
                }
                else
                {
                    // 在按钮名称数组中查找对应的按钮
                    int i = Array.IndexOf(rcbtmc, cellValue);
                    if (i >= 0)
                    {
                        // 找到对应按钮,使用按钮编辑器
                        e.RepositoryItem = rcbt[i];
                    }
                    else
                    {
                        // 未找到,使用默认文本编辑器
                        e.RepositoryItem = rctt;
                    }
                }
            }
            catch (Exception)
            {
                // 静默处理异常
            }
        }

        /// <summary>
        /// 获取数据库连接状态
        /// 将System.Data.ConnectionState枚举转换为中文描述
        /// </summary>
        /// <returns>数据库连接状态的中文描述</returns>
        private string Gethydbzt()
        {
            string zt = "未知";
            switch (KcDb.KcCn.State)
            {
                case ConnectionState.Broken:
                    zt = "已经中断";
                    break;
                case ConnectionState.Open:
                    zt = "已经打开";
                    break;
                case ConnectionState.Closed:
                    zt = "已经关闭";
                    break;
                case ConnectionState.Connecting:
                    zt = "正在连接";
                    break;
                case ConnectionState.Executing:
                    zt = "正在执行命令";
                    break;
            }
            return zt;
        }

        /// <summary>
        /// 获取展开模块设置
        /// 读取布局控件中展开的分组,保存到设置中
        /// </summary>
        /// <param name="mklc">布局控件(如业务处理、信息查询、基础资料面板)</param>
        private void GetZkMk(LayoutControl mklc)
        {
            try
            {
                string ywmk = ""; // 用于存储展开模块的字符串
                LayoutControlGroup lc;
                
                // 遍历布局控件的根项
                for (int l = 0; l < mklc.Root.Items.Count; l++)
                {
                    if (mklc.Root.Items[l].IsGroup) // 如果是分组
                    {
                        lc = (LayoutControlGroup)mklc.Root.Items[l];
                        if (lc != null)
                        {
                            if (lc.Expanded) // 如果分组是展开状态
                            {
                                if (ywmk == "")
                                {
                                    ywmk = lc.Text; // 第一个模块
                                }
                                else
                                {
                                    ywmk += "`" + lc.Text; // 用`分隔多个模块
                                }
                            }
                        }
                    }
                }
                
                // 保存到设置中
                FmSave(mklc.Name + "展开模块", ywmk);
            }
            catch (Exception)
            {
                // 静默处理异常
            }
        }

        /// <summary>
        /// 任务链接按钮点击事件
        /// 处理任务列表中的操作按钮点击,执行相应的任务处理功能
        /// 设计特点:基于工作流引擎的任务驱动处理
        /// </summary>
        private void Ljcx_Buttonclick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
        {
            try
            {
                string ljgnmc = e.Button.Caption; // 获取按钮文本(功能名称)
                
                // 从当前行获取任务相关参数
                object ljrwlbObj = rwgv.GetRowCellValue(rwgv.FocusedRowHandle, rwgv.Columns["rwly"]);
                string ljrwlb = ljrwlbObj != null ? ljrwlbObj.ToString() : ""; // 任务来源
                
                object ljrwxhObj = rwgv.GetRowCellValue(rwgv.FocusedRowHandle, rwgv.Columns["rwbh"]);
                string ljrwxh = ljrwxhObj != null ? ljrwxhObj.ToString() : ""; // 任务编号
                
                object ljrwidObj = rwgv.GetRowCellValue(rwgv.FocusedRowHandle, rwgv.Columns["rwid"]);
                string ljrwid = ljrwidObj != null ? ljrwidObj.ToString() : ""; // 任务ID
                
                object ljbpidObj = rwgv.GetRowCellValue(rwgv.FocusedRowHandle, rwgv.Columns["bpid"]);
                string ljbpid = ljbpidObj != null ? ljbpidObj.ToString() : ""; // 流程实例ID
                
                object ljsqryObj = rwgv.GetRowCellValue(rwgv.FocusedRowHandle, rwgv.Columns["sqry"]);
                string ljsqry = ljsqryObj != null ? ljsqryObj.ToString() : ""; // 申请人员
                
                // 权限验证:当前用户是否在申请人员列表中
                if (!ljsqry.Contains(pDQYH))
                {
                    return; // 无权限,直接返回
                }
                
                // 从权限表中查找该功能
                DataRow[] dr = pDTQX.Select("gnmc='" + ljgnmc + "'");
                if (dr.Length > 0)
                {
                    string fl = dr[0]["gnly"].ToString(); // 功能类别
                    string bh = dr[0]["gnbh"].ToString(); // 功能编号
                    string xz = dr[0]["xzqx"].ToString(); // 执行权限
                    
                    // 特定类别功能需要传递流程实例ID(bpid)
                    if ((fl == "单据输入" || fl == "单据审批" || fl == "单据查询" || fl == "工资计件") && ljbpid != "")
                    {
                        // 调用功能执行方法,传递流程实例ID
                        X9gn(ljgnmc, fl, bh, xz, null, ljbpid);
                    }
                    else
                    {
                        // 普通功能执行
                        X9gn(ljgnmc, fl, bh, xz, null, null);
                    }
                }
                else
                {
                    MsgOxShow("当前操作员无此权限"); // 显示无权限提示
                }
                
                KcDb.DBclose(); // 关闭数据库连接
            }
            catch (Exception ex)
            {
                MsgExShow("执行链接任务", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 主初始化方法:完成所有启动时必要的加载
        /// 这是系统的核心初始化流程,调用链中的关键方法
        /// </summary>
        private void LoadForm()
        {
            this.Text = ""; // 清空窗口标题
            
            // 1. 显示启动进度窗口
            FmSp fgy = new FmSp(); // 启动画面/进度窗口
            fgy.Show(this);
            
            // 2. 创建数据目录结构
            pDataPath = pDataRoot + "\\" + pDBmc; // 数据库专用数据路径
            if (!System.IO.Directory.Exists(pDataPath))
            {
                System.IO.Directory.CreateDirectory(pDataPath);
            }
            
            // 备份目录
            pBak = pDataPath + "\\bak";
            if (!System.IO.Directory.Exists(pBak))
            {
                System.IO.Directory.CreateDirectory(pBak);
            }
            
            // 日志目录
            pFilesLog = pDataPath + "\\log";
            if (!System.IO.Directory.Exists(pFilesLog))
            {
                System.IO.Directory.CreateDirectory(pFilesLog);
            }
            
            // 文件存储目录
            pFilesLC = pDataPath + "\\files";
            if (!System.IO.Directory.Exists(pFilesLC))
            {
                System.IO.Directory.CreateDirectory(pFilesLC);
            }
            
            // 临时文件目录
            pFilesTemp = pDataPath + "\\temp";
            if (!System.IO.Directory.Exists(pFilesTemp))
            {
                System.IO.Directory.CreateDirectory(pFilesTemp);
            }
            
            // 报表目录
            pFilesReport = pDataPath + "\\rpt";
            if (!System.IO.Directory.Exists(pFilesReport))
            {
                System.IO.Directory.CreateDirectory(pFilesReport);
            }
            
            // 查询文件目录
            pFilesQuery = pDataPath + "\\query";
            if (!System.IO.Directory.Exists(pFilesQuery))
            {
                System.IO.Directory.CreateDirectory(pFilesQuery);
            }
            
            // XML文件目录
            pFilesXml = pDataPath + "\\xml";
            if (!System.IO.Directory.Exists(pFilesXml))
            {
                System.IO.Directory.CreateDirectory(pFilesXml);
            }
            
            // 3. 设置软件标题
            pZTMC = "看潮企业管理软件";
            fgy.LZTMC.Text = pZTMC;
            fgy.Refresh();
            RibbonControl.ApplicationCaption = pZTMC;
            
            string pcinfo = "";
            try
            {
                // 4. 记录PC信息并获取用户权限
                pcinfo = GetPc(); // 获取PC硬件信息
                
                // 记录PC使用信息到数据库
                string exesql = "select x9_pcxh('" + pPCBH + "','" + pBJMC + " " + pRJBB + "','" + pDQYH + "','" + pcinfo + "')";
                pPCXH = KcDb.DBexec(exesql); // 执行存储过程,返回PC序号
                
                // 获取用户信息
                pYHXH = KcDb.DBString("select yhbh from x9_gnyh where yhmc='" + pDQYH + "'"); // 用户编号
                pDQBM = KcDb.DBString("select yhbm from x9_gnyh where yhmc='" + pDQYH + "'"); // 用户部门
                
                // 5. 加载账套参数
                pDTCS = KcDb.DtRead("select id,cslx, csmc, szjg, zfjg, ljjg from x9_ztcs"); // 读取账套参数表
                
                // 获取常用参数
                pSYDW = GetZfcs("使用单位", "");         // 使用单位名称
                pMCSX = GetZfcs("单位名称缩写", "");     // 单位简称
                pDWYJ = GetZfcs("单位邮件地址", "");     // 单位邮箱
                pCPDH = GetZfcs("授权产品代号", "1201"); // 产品代号
                pZSBH = GetZfcs("授权证书编号", "");     // 证书编号
                
                // 重新设置软件标题(确保显示正确的账套名称)
                pZTMC = "看潮企业管理软件";
                fgy.LZTMC.Text = pZTMC;
                fgy.Refresh();
                RibbonControl.ApplicationCaption = pZTMC;
                
                // 6. 加载本地配置参数
                pSBGS = GetLjcs("鼠标跟随", false);              // 鼠标跟随功能
                pSBZY = GetLjcs("鼠标跟随定位窗体中央", false); // 鼠标定位到窗体中央
                pGDRQ = GetLjcs("使用手动业务日期", false);     // 是否使用手动业务日期
                pCSGS = GetLjcs("测试计算公式", false);         // 计算公式测试
                pZDHH = GetLjcs("单据自动行号", true);          // 自动行号
                pCXCX = GetLjcs("重新查询", true);              // 重新查询
                pDWDZ = GetZfcs("单位地址", "");                // 单位地址
                pDWLX = GetZfcs("单位联系方式", "");            // 单位联系方式
                pMaxWt = GetSzcs("表格配置最大列宽", 120);      // 表格最大列宽
                pMinWt = GetSzcs("表格配置最小列宽", 50);       // 表格最小列宽
            }
            catch (Exception ex)
            {
                // 静默处理参数加载异常
            }
            
            try
            {
                // 7. 加载文件关联设置
                if (Directory.Exists(pAppPath + "sdfilesseting.xml"))
                {
                    pGLWJ.ReadXml(pAppPath + "sdfilesseting.xml"); // 读取XML配置文件
                }
            }
            catch (Exception ex)
            {
                fgy.Dispose();
                pGLWJ = null;
                MsgExShow("加载文件关联应用程序文件sdfilesseting.xml", ex.Message, ex.Source, ex.StackTrace);
            }
            
            try
            {
                // 8. 加载窗口参数数据集
                pDSFM = new DataSet();
                if (File.Exists(cslj + pDBmc + "_" + myscreen + ".xml"))
                {
                    // 如果存在保存的窗口参数文件,读取它
                    pDSFM.ReadXml(cslj + pDBmc + "_" + myscreen + ".xml");
                    pDSFM.AcceptChanges(); // 标记为未修改
                }
                else
                {
                    // 否则创建空的参数表
                    pDSFM.Tables.Add(Makefmdt());
                }
            }
            catch (Exception ex)
            {
                fgy.Dispose();
                MsgExShow("加载窗口参数文件formset" + pDBmc + pDLmc + ".xml", ex.Message, ex.Source, ex.StackTrace);
            }
            
            try
            {
                // 9. 设置默认选中的Ribbon页
                RibbonControl.SelectedPage = RibbonControl.Pages[0];
                fgy.Refresh();
                
                // 更新进度显示
                fgy.JD.Text = "...正在打开数据库[" + pDBmc + "]...";
                fgy.jdleft();
                fgy.Refresh();
                
                // 根据是否为设计模式显示不同的Ribbon页
                if (pSFSJ) // 设计模式
                {
                    RibbonControl.SelectedPage = RibbonPageSJ;
                    RibbonPageSJ.Visible = true;
                }
                else // 运行模式
                {
                    RibbonControl.SelectedPage = RibbonPageZT;
                    RibbonPageSJ.Visible = false;
                }
                
                // 10. 加载菜单图片
                fgy.JD.Text = "...正在加载菜单图片...";
                fgy.jdleft();
                fgy.Refresh();
                
                // 定义需要加载图片的菜单项名称
                string[] cdname;
                string fmgnmc = "载入,提交,帮助,返回,预览,打印,确定,取消,删除,添加同级,添加下级,展开,收起,查找"; // 基础功能
                fmgnmc += ",公式重算,标记或取消审核,布局方向切换,文件导出,文件导入"; // 数据处理功能
                fmgnmc += ",调入,添加,修改,键盘,作废,审核,登记"; // 单据操作功能
                fmgnmc += ",流转,回退,全部流转,全部回退"; // 工作流功能
                fmgnmc += ",编辑,验证,全部审核,全部登记,部分审核,部分登记,连续预览,连续打印"; // 审批功能
                fmgnmc += ",执行,连接,暂存,编码转换,文件下载,升级工具,设计文件"; // 系统工具
                fmgnmc += ",列赋值,列清空,列替换,设计字典,系统字典,功能字典"; // 数据字典
                fmgnmc += ",重新启动,重新连接,用户密码,用户信息,运行,迁移,版权信息,设置皮肤,退出"; // 主窗口功能
                fmgnmc += ",功能列表,分类目录,查询输入,关联输入,单据输入,单据审批,业务处理,单据查询,汇总查询"; // 设计功能
                fmgnmc += ",复制功能定义,复制计算公式,复制输入限制,导入功能定义,当前功能运行测试,多选模式"; // 高级功能
                
                // 设置图片目录
                pTBZD = "image" + pCDTB; // 如:image1、image2、image3
                string tname = "";
                Image newimage = null;
                pCdimage.ImageSize = new Size(32, 32); // 设置图标大小
                
                // 分割菜单项名称
                cdname = fmgnmc.Split(',');
                for (int r = 0; r < cdname.Length; r++)
                {
                    if (cdname[r].Trim() != "")
                    {
                        tname = cdname[r].ToString().Trim() + ".png"; // 图片文件名
                        if (File.Exists(cslj + "\\" + pTBZD + "\\CD" + tname))
                        {
                            // 加载图片到图像集合
                            newimage = Image.FromFile(cslj + "\\" + pTBZD + "\\CD" + tname);
                            pCdimage.Images.Add(newimage, cdname[r].ToString().Trim());
                        }
                    }
                }
                
                // 将图片应用到Ribbon按钮
                if (pCdimage.Images.Count > 0)
                {
                    foreach (BarItem item in RibbonControl.Items)
                    {
                        if (item.GetType().Name.ToLower() == "barbuttonitem") // 只处理按钮项
                        {
                            if (pCdimage.Images.Keys.IndexOf(item.Caption) >= 0)
                            {
                                item.LargeGlyph = pCdimage.Images[item.Caption]; // 设置大图标
                            }
                        }
                    }
                }
                
                // 11. 加载功能模块图标
                fgy.JD.Text = "...正在加载功能图片...";
                fgy.jdleft();
                fgy.Refresh();
                
                // 从数据库读取功能模块列表
                dtgntp = KcDb.DtRead("select mkmc from x9_gn_gnmk");
                int tprows = dtgntp.Rows.Count - 1;
                gnimage.ImageSize = new Size(32, 32); // 功能图标大小
                string wjex = ""; // 记录找不到的图片文件
                
                for (int i = 0; i <= tprows; i++)
                {
                    try
                    {
                        tname = dtgntp.Rows[i]["mkmc"].ToString() + ".png"; // 模块图片文件名
                        if (File.Exists(cslj + "\\" + pTBZD + "\\MK" + tname))
                        {
                            newimage = System.Drawing.Image.FromFile(cslj + "\\" + pTBZD + "\\MK" + tname);
                            gnimage.Images.Add(newimage, dtgntp.Rows[i]["mkmc"].ToString());
                        }
                    }
                    catch (Exception ex)
                    {
                        wjex += tname + "\r\n"; // 记录错误文件名
                    }
                }
                
                // 如果有找不到的图片,记录到日志文件
                if (wjex != "")
                {
                    CreateTextFile(pFilesLog + "\\没有找到文件的图标" + DateTime.Now.ToString("yyyyMMddhhsstt") + ".txt", wjex);
                }
                wjex = null;
                
                // 12. 加载用户权限
                pDTQX = null;
                pYHJS = KcDb.DBString("select yhjs from x9_gnyh where yhmc='" + pDQYH + "'"); // 用户角色
                
                string gnsql = "";
                if (sqmk == "")
                {
                    // 默认授权模块(如果未特别指定)
                    sqmk = "'分类目录','基础设置','系统维护','系统设计','文件资料管理','人事档案管理'";
                }
                
                // 构建权限查询SQL:联合用户权限表和功能模块表
                gnsql = "select qx.gnbh, qx.gnmc, qx.gnly, qx.gnlb, qx.ssmk, min(qx.jzzd) as jzzd, max(qx.xzqx) as xzqx, mk.mkxh, qx.sfyc,qx.zjm " +
                       " from x9_gnyhqx as qx inner join  x9_gn_gnmk as mk on qx.ssmk = mk.mkmc and mk.sfyy=true " +
                       " where position(qx.yhjs in '" + pYHJS + "') > 0 and (qx.sfsq = true) " +
                       " group by qx.gnbh, qx.gnmc, qx.gnly, qx.gnlb, qx.ssmk,mk.mkxh,qx.sfyc,qx.zjm " +
                       " order by mk.mkxh, qx.gnbh";
                
                pDTQX = KcDb.DtRead(gnsql); // 执行查询,获取用户有权限的功能列表
                
                // 13. 读取账套选项和参数
                fgy.JD.Text = "...正在读取账套选项和参数...";
                fgy.jdleft();
                fgy.Refresh();
                
                // 获取表格行高参数
                PanelRowHeight = GetSzcs("表格标题高度", 36);
                if (pDTCS.DataSet.HasChanges())
                {
                    // 如果有参数更改,保存到数据库
                    KcDb.GetDtSaven("x9_ztcs", pDTCS.GetChanges());
                    pDTCS.AcceptChanges();
                }
                if (PanelRowHeight < 28) PanelRowHeight = 28; // 最小行高限制
                
                PanelRowHeightJj = GetSzcs("计件工作量标题高度", 36); // 计件表格行高
                if (PanelRowHeightJj < 28) PanelRowHeightJj = 28;
                
                // 自动调整参数范围检查
                if (pAUTO < 10 || pAUTO > 36) pAUTO = 10;
                
                // 14. 设置业务期间和日期
                pQYQJ = KcDb.DBString("select min(ny) as ny from mlny"); // 最早业务期间
                pYWQJ = KcDb.DBString("select max(ny) as ny from mlny"); // 当前业务期间
                pYWRQ = Convert.ToDateTime(GetZfcs("手动业务日期", 
                    pYWQJ.Substring(0, 4) + "-" + pYWQJ.Substring(4, 2) + "-" + "01")); // 默认设为期间第一天
                
                Tsywrq.EditValue = pYWRQ; // 更新界面控件
                
                // 15. 更新状态栏信息
                ts1.Caption = "[账套用户:" + pDQYH + " " + pYHJS + "]"; // 用户信息
                ts3.Caption = "[业务期间:" + pYWQJ + "]";              // 业务期间
                LcYxZt.Text = "[" + pSYDW + "]" + "[" + pZTMC + "]" + "[" + pDBmc + "]" + 
                             (pSFSJ ? "[设计]" : "[运行]"); // 运行状态
                
                RibbonControl.ApplicationDocumentCaption = pSYDW; // 文档标题
                RibbonControl.ApplicationCaption = pZTMC;         // 应用程序标题
                
                // 16. 动态加载三个主要功能面板
                // 基础资料面板
                DataRow[] dr = pDTQX.Select("(gnlb='基础资料') and sfyc=false", "mkxh,gnbh");
                MyGn("基础资料", dr, PgJC, jclc);
                
                // 信息查询面板
                dr = pDTQX.Select("(gnlb='信息查询') and sfyc=false", "mkxh,gnbh");
                MyGn("信息查询", dr, PGxx, xxlc);
                
                // 业务处理面板
                dr = pDTQX.Select("gnlb='业务处理' and sfyc=false", "mkxh,gnbh");
                MyGn("业务处理", dr, PGyw, ywlc);
            }
            catch (Exception ex)
            {
                fgy.Dispose();
                MsgExShow("装入程序菜单", ex.Message, ex.Source, ex.StackTrace);
                return;
            }
            
            try
            {
                // 17. 保存账套参数更改(如果有)
                if (pDTCS.DataSet.HasChanges())
                {
                    KcDb.GetDtSaven("x9_ztcs", pDTCS.GetChanges());
                    pDTCS.AcceptChanges();
                }
            }
            catch (Exception ex)
            {
                MsgExShow("保存账套参数", ex.Message, ex.Source, ex.StackTrace);
            }
            
            try
            {
                // 18. 加载打印机列表
                string pkinstalledprinters;
                string pddefaultprinter;
                PrintDocument printdoc = new PrintDocument();
                pddefaultprinter = printdoc.PrinterSettings.PrinterName; // 默认打印机
                
                // 遍历系统安装的所有打印机
                for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++)
                {
                    pkinstalledprinters = PrinterSettings.InstalledPrinters[i];
                    printdoc.PrinterSettings.PrinterName = pkinstalledprinters;
                    if (printdoc.PrinterSettings.IsValid) // 检查打印机是否有效
                    {
                        RcPt1.Items.Add(pkinstalledprinters); // 添加到下拉列表
                    }
                }
                
                // 设置默认打印机
                BarDqpt.EditValue = pddefaultprinter;
                pPrinterName = pddefaultprinter;
            }
            catch (Exception ex)
            {
                MsgExShow("加载打印机列表", ex.Message, ex.Source, ex.StackTrace);
            }
            
            try
            {
                // 19. 加载任务列表
                LoadRwgv(GridRW, rwgv);
            }
            catch (Exception ex)
            {
                fgy.Dispose();
                this.Refresh();
                MsgExShow("加载我的任务表格视图", ex.Message, ex.Source, ex.StackTrace);
            }
            
            // 20. 检查是否为技术服务人员
            if (ts5.Caption.Contains("[技术服务人员]"))
            {
                pWHRY = true; // 设置技术服务人员标志
            }
            
            // 21. 读取屏幕参数
            fgy.JD.Text = "...正在读取屏幕参数...";
            fgy.jdleft();
            fgy.Refresh();
            fgy.Dispose(); // 关闭启动进度窗口
            
            try
            {
                // 22. 应用保存的窗口设置
                string fmset = FmRead("主窗口");
                string[] fmay = fmset.Split(',');
                if (fmay.Length >= 7)
                {
                    Int16 ws = 0;
                    if (fmay.Length == 7)
                    {
                        ws = Convert.ToInt16(fmay[6]); // 窗口状态(0正常,1最小化,2最大化)
                        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]) > 800) this.Width = Convert.ToInt32(fmay[2]); // 宽度
                        if (Convert.ToInt32(fmay[3]) > 500) this.Height = Convert.ToInt32(fmay[3]); // 高度
                    }
                    if (Convert.ToInt32(fmay[4]) > 50) Sp1.SplitterPosition = Convert.ToInt32(fmay[4]); // 分割器位置
                    GNTab.SelectedTabPageIndex = Convert.ToInt32(fmay[5]); // 选中的标签页索引
                }
            }
            catch (Exception ex)
            {
                fgy.Dispose();
                MsgExShow("应用窗口参数", ex.Message, ex.Source, ex.StackTrace);
            }
            
            this.Refresh();
            this.Visible = true; // 显示主窗口
            
            try
            {
                // 23. 安全检查:提示设置密码(如果用户没有密码)
                if (KcDb.DBString("select yhmm from x9_gnyh where yhmc='" + pDQYH + "'") == "")
                {
                    MsgXxShow("为保证您的安全使用,请设置您的登录密码");
                    FmYHMM fmm = new FmYHMM();
                    fmm.ShowDialog(this); // 强制用户设置密码
                }
            }
            catch (Exception ex)
            {
                MsgExShow("打开用户密码设置窗口", ex.Message, ex.Source, ex.StackTrace);
            }
            
            try
            {
                // 24. 验证业务期间与业务日期的一致性
                if (pYWQJ != pYWRQ.ToString("yyyyMM"))
                {
                    MsgXxShow("当前业务期间与业务日期不一致,请谨慎操作。请系统管理员在月末时及时完成月末处理!");
                }
            }
            catch (Exception ex)
            {
                MsgExShow("验证业务期间与业务日期的一致性", ex.Message, ex.Source, ex.StackTrace);
            }
            
            try
            {
                // 25. 设计模式下清理异常日志
                if (pSFSJ) // 如果是设计模式
                {
                    int yxzt = 0;  // 运行状态记录数
                    int qdcw = 0;  // 客户端错误数
                    int hdcw = 0;  // 服务端错误数
                    int sqljl = 0; // SQL记录数
                    
                    // 统计各种异常记录
                    yxzt = KcDb.DBInteger("select count(*) from x9_yxzt");
                    sqljl = KcDb.DBInteger("select count(*) from x9_jlsql");
                    hdcw = KcDb.DBInteger("select count(*) from x9_errproc");
                    qdcw = KcDb.DBInteger("select count(*) from x9_errcode");
                    
                    // 如果有异常记录,提示用户是否清理
                    if ((yxzt + qdcw + hdcw + sqljl) > 0)
                    {
                        if (MsgSfShow("    运行状态数: " + yxzt.ToString().Trim() + "\r\n    数据访问数: " + sqljl.ToString().Trim() + "\r\n" +
                                  "    服务端异常: " + hdcw.ToString().Trim() + "\r\n    客户端异常: " + qdcw.ToString().Trim() + "\r\n\r\n" +
                                  "是否直接删除这些记录?") == DialogResult.OK)
                        {
                            // 用户确认,清理所有异常记录
                            KcDb.DBexec("delete from x9_yxzt");
                            KcDb.DBexec("delete from x9_errcode");
                            KcDb.DBexec("delete from x9_errproc");
                            KcDb.DBexec("delete from x9_jlsql");
                        }
                    }
                }
                KcDb.DBclose(); // 关闭数据库连接
            }
            catch (Exception ex)
            {
                MsgExShow("系统异常日志提示", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 加载任务列表到网格视图
        /// 从数据库读取当前用户的任务,并动态配置网格列
        /// </summary>
        /// <param name="gd">网格控件</param>
        /// <param name="gv">网格视图</param>
        private void LoadRwgv(GridControl gd, GridView gv)
        {
            try
            {
                DataTable dt = new DataTable();
                string rwsql;
                
                // 设置任务标题
                Trwdb.Text = "[" + pYHJS + "][" + pDQYH + "]工作任务 ";
                
                // 构建任务查询SQL:查询当前用户相关的任务
                rwsql = "select rwid,djmc,bpid,rwbh,rwmc,zrry,sqry,wcsj,wcry,rwzy,rwexec,sfwc " +
                    "from x9_bprw where (position('" + pDQYH + "'in sqry)>0  or position('系统管理员' in '" + pYHJS +
                        "') > 0 or sqry='') order by sfwc,rwid desc limit 300"; // 最多300条记录
                
                dt = KcDb.DtRead(rwsql); // 执行查询
                
                // 清空现有视图集合
                gd.ViewCollection.Clear();
                gv = new GridView(gd); // 创建新的网格视图
                gv.BeginUpdate(); // 开始批量更新,提高性能
                
                gv.Name = "rwgv";
                gv.OptionsBehavior.AutoPopulateColumns = false; // 手动配置列
                gd.DataSource = dt; // 设置数据源
                gd.ForceInitialize(); // 强制初始化
                gd.MainView = gv; // 设置主视图
                gv.PopulateColumns(dt); // 根据数据表结构创建列
                
                SetGv(ref gv, true); // 设置网格基本属性
                gv.OptionsView.ShowFooter = false; // 不显示页脚
                gv.OptionsBehavior.AutoUpdateTotalSummary = false; // 不自动更新汇总
                gv.OptionsSelection.MultiSelect = true; // 允许多选
                gv.OptionsSelection.MultiSelectMode = GridMultiSelectMode.RowSelect; // 行选择模式
                gv.OptionsView.EnableAppearanceEvenRow = true; // 启用交替行背景色
                gv.OptionsView.EnableAppearanceOddRow = true;
                
                // 读取任务表的列定义(数据字典)
                string zdsql = "select * from x9_sjzd where zdbb='' and tname='x9_bprw' and fmemo<>'' order by fxh";
                DataTable dtzd = new DataTable();
                dtzd = KcDb.DtRead(zdsql);
                
                // 绑定右键菜单事件
                gv.PopupMenuShowing += new DevExpress.XtraGrid.Views.Grid.PopupMenuShowingEventHandler(this.Mtgv_PopupMenuShowing);
                
                if (dtzd != null && dtzd.Rows.Count > 0)
                {
                    // 根据数据字典配置网格列
                    Gdlomyrw(ref gd, ref gv, ref dtzd);
                    gv.OptionsBehavior.ReadOnly = true; // 设置为只读
                    
                    // 收集所有不同的操作按钮名称
                    string btmc = "";
                    string dqmc = "";
                    for (int r = 0; r < gv.RowCount; r++)
                    {
                        object cv = gv.GetRowCellValue(r, gv.Columns["rwexec"]);
                        if (cv != null)
                        {
                            dqmc = "[" + cv.ToString().Trim() + "]"; // 用方括号包裹
                        }
                        if (dqmc != "" && !btmc.Contains(dqmc))
                        {
                            btmc += dqmc + ","; // 用逗号分隔
                        }
                    }
                    
                    // 如果有操作按钮,创建对应的编辑器
                    if (btmc != "")
                    {
                        // 处理按钮名称数组
                        rcbtmc = btmc.Substring(0, btmc.Length - 1).Split(','); // 去掉最后一个逗号并分割
                        rcbt = new RepositoryItemButtonEdit[rcbtmc.Length];
                        
                        // 去掉方括号
                        for (int i = 0; i < rcbtmc.Length; i++)
                        {
                            rcbtmc[i] = rcbtmc[i].Substring(1, rcbtmc[i].Length - 2);
                        }
                        
                        // 创建按钮编辑器
                        for (int i = 0; i < rcbtmc.Length; i++)
                        {
                            if (rcbtmc[i] != "")
                            {
                                RepositoryItemButtonEdit rc = new RepositoryItemButtonEdit
                                {
                                    TextEditStyle = TextEditStyles.HideTextEditor // 隐藏文本编辑器,只显示按钮
                                };
                                rc.Buttons.Clear();
                                
                                // 创建按钮
                                DevExpress.XtraEditors.Controls.EditorButton bt1 = new DevExpress.XtraEditors.Controls.EditorButton
                                {
                                    Caption = rcbtmc[i], // 按钮文本
                                    Kind = ButtonPredefines.Glyph // 按钮类型
                                };
                                rc.Buttons.Add(bt1);
                                rcbt[i] = rc;
                                gd.RepositoryItems.Add(rcbt[i]); // 添加到网格编辑器集合
                                rcbt[i].ButtonClick += Ljcx_Buttonclick; // 绑定按钮点击事件
                            }
                        }
                        
                        // 绑定自定义单元格编辑器事件
                        gv.CustomRowCellEdit += Gdgv_Customrowcelledit;
                    }
                }
                
                gv.EndUpdate(); // 结束批量更新
                gd.Tag = "gvend"; // 设置标记,表示网格已初始化完成
                gd.UseEmbeddedNavigator = false; // 不使用内置导航器
                
                // 隐藏不需要显示的列
                gv.Columns["rwbh"].Visible = false; // 任务编号
                gv.Columns["rwmc"].Visible = false; // 任务名称
                gv.Columns["sqry"].Visible = false; // 申请人员
                gd.Visible = true; // 显示网格
                
                // 应用保存的列宽和行高设置
                string fmset = FmRead("任务表格列宽行高");
                string[] fmay = fmset.Split(',');
                if (fmay.Length == gv.VisibleColumns.Count + 1) // 列宽数+行高
                {
                    for (int c = 0; c < gv.VisibleColumns.Count; c++)
                    {
                        gv.VisibleColumns[c].Width = Convert.ToInt32(fmay[c]); // 设置列宽
                    }
                    if (Convert.ToInt32(fmay[fmay.Length - 1]) > 10)
                    {
                        gv.RowHeight = Convert.ToInt32(fmay[fmay.Length - 1]); // 设置行高
                    }
                }
                else
                {
                    // 如果没有保存的设置,自动配置列宽
                    Gvoptionwithmin(ref gv, gd.Width);
                }
            }
            catch (Exception ex)
            {
                MsgExShow("加载任务列表", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 网格右键菜单显示事件
        /// 在网格的右键菜单中添加自定义菜单项
        /// </summary>
        private void Mtgv_PopupMenuShowing(object sender, DevExpress.XtraGrid.Views.Grid.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 += (s, args) => Dxmenuclick(); // 绑定点击事件
                    e.Menu.Items.Add(dxmenu);
                    
                    // 添加"手动配置列宽"菜单项
                    DXMenuItem dxmenusd = new DXMenuItem();
                    dxmenusd.Caption = "手动配置列宽";
                    dxmenusd.Click += (s, args) => Dxsdclick(); // 绑定点击事件
                    e.Menu.Items.Add(dxmenusd);
                }
            }
            catch (Exception ex)
            {
                MsgExShow("增加配置列宽右键菜单", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 加载功能菜单的核心方法
        /// 根据用户权限动态生成左侧导航面板(基础资料/信息查询/业务处理)
        /// 设计模式:基于角色权限过滤 + 按模块分组展示 + 图标支持
        /// </summary>
        /// <param name="gnlb">功能类别:基础资料/信息查询/业务处理</param>
        /// <param name="dr">功能数据行数组(已按权限过滤)</param>
        /// <param name="pg">XtraTabPage标签页控件</param>
        /// <param name="gnlc">LayoutControl布局控件</param>
        private void MyGn(string gnlb, DataRow[] dr, XtraTabPage pg, LayoutControl gnlc)
        {
            try
            {
                // 1. 初始化布局控件
                gnlc.Name = gnlb;
                pg.Controls.Clear(); // 清空标签页原有控件
                pg.Controls.Add(gnlc); // 添加布局控件到标签页
                gnlc.Dock = DockStyle.Fill; // 填充整个标签页
                
                // 2. 配置布局控件属性
                gnlc.OptionsCustomizationForm.ShowLoadButton = false; // 不显示加载按钮
                gnlc.OptionsCustomizationForm.ShowSaveButton = false; // 不显示保存按钮
                gnlc.OptionsCustomizationForm.AllowHandleDeleteKey = true; // 允许删除键
                gnlc.OptionsCustomizationForm.ShowPropertyGrid = true; // 显示属性网格
                gnlc.AllowCustomization = false; // 不允许用户自定义布局
                
                // 3. 从保存的设置中读取哪些模块是展开的
                string mkset = FmRead(gnlb + "展开模块");
                string[] mkay = mkset.Split('`'); // 使用`作为分隔符
                
                gnlc.BeginUpdate(); // 开始批量更新,提高性能
                gnlc.Root.Clear(); // 清空根节点
                
                // 4. 如果有功能数据,动态生成功能菜单
                if (dr.Length > 0)
                {
                    int i = -1;
                    string gnssmk = ""; // 当前模块名称,用于检测模块变化
                    LayoutControlGroup dqgp = new LayoutControlGroup(); // 当前分组控件
                    
                    // 遍历所有功能数据行
                    for (int j = 0; j < dr.Length; j++)
                    {
                        i++;
                        
                        // 5. 检测模块变化:如果遇到新模块,创建新的分组
                        if (dr[j]["ssmk"].ToString() != gnssmk)
                        {
                            dqgp = new LayoutControlGroup();
                            dqgp.Name = "ktxx" + i.ToString("000"); // 生成唯一名称
                            dqgp.Text = dr[j]["ssmk"].ToString(); // 模块名称作为分组标题
                            dqgp.AllowHide = true; // 允许隐藏
                            dqgp.TextSize = new Size(100, 28); // 标题大小
                            dqgp.TextVisible = true; // 显示标题
                            dqgp.ExpandButtonVisible = true; // 显示展开/收起按钮
                            dqgp.ExpandOnDoubleClick = true; // 双击展开/收起
                            dqgp.HeaderButtonsLocation = GroupElementLocation.AfterText; // 按钮位置
                            dqgp.GroupBordersVisible = true; // 显示分组边框
                            dqgp.AllowCustomizeChildren = false; // 不允许自定义子项
                            dqgp.Expanded = false; // 默认收起
                            
                            // 根据保存的设置决定分组是否展开
                            if (Array.IndexOf(mkay, dqgp.Text) > -1)
                            {
                                dqgp.Expanded = true; // 如果是之前展开的模块,保持展开状态
                            }
                            
                            gnlc.AddGroup(dqgp); // 将分组添加到布局控件
                        }
                        
                        // 6. 为每个功能创建一个按钮项
                        LayoutControlItem litem = new LayoutControlItem
                        {
                            FillControlToClientArea = false // 不填充客户区
                        };
                        
                        // 创建功能按钮
                        SimpleButton xc = new SimpleButton
                        {
                            Name = "txx" + i.ToString("000"), // 唯一名称
                            Text = dr[j]["gnmc"].ToString() // 功能名称
                        };
                        xc.Cursor = Cursors.Hand; // 手型光标
                        
                        // 设置功能图标(从ImageCollection中获取)
                        if (gnimage.Images.Keys.IndexOf(dr[j]["ssmk"].ToString()) >= 0)
                        {
                            xc.Image = gnimage.Images[dr[j]["ssmk"].ToString()];
                        }
                        
                        // 在Tag中存储功能执行的必要参数(逗号分隔)
                        // 格式:功能名称,功能来源,功能编号,执行权限,功能类别
                        xc.Tag = dr[j]["gnmc"].ToString().Trim() + "," + 
                                 dr[j]["gnly"].ToString().Trim() + "," +
                                 dr[j]["gnbh"].ToString().Trim() + "," + 
                                 dr[j]["xzqx"] + "," + gnlb;
                        
                        xc.Enabled = true; // 启用按钮
                        xc.Click += RunGncd; // 绑定点击事件
                        xc.MinimumSize = new Size(100, 28); // 最小尺寸
                        
                        litem.Name = "ixx" + i.ToString("000");
                        litem.Control = xc; // 设置按钮控件
                        litem.MinSize = new Size(100, 28); // 最小尺寸
                        litem.Text = dr[j]["gnmc"].ToString(); // 与按钮文本相同
                        litem.Tag = xc.Tag; // 复制Tag
                        litem.TextVisible = false; // 不显示文本(按钮上已有文本)
                        
                        dqgp.AddItem(litem); // 将按钮项添加到当前分组
                        gnssmk = dr[j]["ssmk"].ToString(); // 更新当前模块
                    }
                    
                    gnlc.BestFit(); // 自动调整布局
                    pg.PageVisible = true; // 如果有功能,显示该标签页
                }
                else
                {
                    pg.PageVisible = false; // 无功能,隐藏标签页
                }
                
                gnlc.Tag = gnlb; // 在Tag中存储功能类别
                gnlc.EndUpdate(); // 结束批量更新
            }
            catch (Exception ex)
            {
                MsgExShow("加载" + gnlb + "功能菜单", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 重新加载任务列表
        /// 刷新右侧的"我的任务"列表,获取最新的待办任务
        /// </summary>
        /// <param name="gd">网格控件</param>
        /// <param name="gv">网格视图</param>
        private void Reloadrw(GridControl gd, GridView gv)
        {
            try
            {
                KcDb.DBopen(); // 打开数据库连接
                DataTable dt = new DataTable();
                string rwsql;
                
                // 更新任务标题
                Trwdb.Text = "[" + pYHJS + "][" + pDQYH + "]工作任务 ";
                
                // 构建任务查询SQL(与LoadRwgv相同)
                rwsql = "select rwid,djmc,bpid,rwbh,rwmc,zrry,sqry,wcsj,wcry,rwzy,rwexec,sfwc " +
                    "from x9_bprw where (position('" + pDQYH + "' in sqry)>0  or position('系统管理员' in '" + pYHJS +
                        "') > 0 or sqry='') order by sfwc,rwid desc limit 300";
                
                dt = KcDb.DtRead(rwsql); // 执行查询
                gd.DataSource = dt; // 重新绑定数据源
                gv.ColumnPanelRowHeight = PanelRowHeight; // 设置列标题高度
                gv.RefreshData(); // 刷新显示
                
                if (dt == null || dt.Rows.Count == 0)
                {
                    return; // 没有数据,直接返回
                }
                
                // 更新任务标题,显示任务数量
                Trwdb.Text = "[" + pYHJS + "][" + pDQYH + "]工作任务 [" + dt.Rows.Count.ToString().Trim() + "]";
                
                // 收集所有不同的操作按钮名称(与LoadRwgv逻辑相同)
                string btmc = "";
                string dqmc = "";
                for (int r = 0; r < gv.RowCount; r++)
                {
                    dqmc = "[" + gv.GetRowCellValue(r, gv.Columns["rwexec"]).ToString().Trim() + "]";
                    if (dqmc != "" && !btmc.Contains(dqmc))
                    {
                        btmc += dqmc + ",";
                    }
                }
                
                // 如果有操作按钮,重新创建编辑器
                if (btmc != "")
                {
                    rcbtmc = btmc.Substring(0, btmc.Length - 1).Split(',');
                    rcbt = new RepositoryItemButtonEdit[rcbtmc.Length];
                    for (int i = 0; i < rcbtmc.Length; i++)
                    {
                        rcbtmc[i] = rcbtmc[i].Substring(1, rcbtmc[i].Length - 2);
                    }
                    
                    // 清理现有的按钮编辑器
                    for (int i = gd.RepositoryItems.Count - 1; i >= 0; i--)
                    {
                        if (gd.RepositoryItems[i].EditorTypeName == "buttonedit")
                        {
                            gd.RepositoryItems.RemoveAt(i);
                        }
                    }
                    
                    // 创建新的按钮编辑器
                    for (int i = 0; i < rcbtmc.Length; i++)
                    {
                        if (rcbtmc[i] != "")
                        {
                            RepositoryItemButtonEdit rc = new RepositoryItemButtonEdit
                            {
                                TextEditStyle = TextEditStyles.HideTextEditor
                            };
                            rc.Buttons.Clear();
                            DevExpress.XtraEditors.Controls.EditorButton bt1 = new DevExpress.XtraEditors.Controls.EditorButton
                            {
                                Caption = rcbtmc[i],
                                Kind = ButtonPredefines.Glyph
                            };
                            rc.Buttons.Add(bt1);
                            rcbt[i] = rc;
                            gd.RepositoryItems.Add(rcbt[i]);
                            rcbt[i].ButtonClick += Ljcx_Buttonclick; // 重新绑定事件
                        }
                    }
                    
                    gv.CustomRowCellEdit += Gdgv_Customrowcelledit; // 重新绑定事件
                }
            }
            catch (Exception ex)
            {
                MsgExShow("刷新工作任务", ex.Message, ex.Source, ex.StackTrace);
            }
            finally
            {
                KcDb.DBclose(); // 关闭数据库连接
            }
        }

        /// <summary>
        /// 功能按钮点击事件处理
        /// 解析Tag中的参数并执行对应的功能
        /// 这是左侧导航菜单的核心事件处理器
        /// </summary>
        /// <param name="sender">事件源(SimpleButton按钮)</param>
        /// <param name="e">事件参数</param>
        private void RunGncd(object sender, EventArgs e)
        {
            string[] gntj; // 功能条件数组
            string mc;     // 功能名称
            string bh;     // 功能编号
            string xz;     // 执行权限
            string lb;     // 功能类别
            string ly;     // 功能来源
            
            try
            {
                SimpleButton rx = (SimpleButton)sender; // 获取触发事件的按钮
                gntj = rx.Tag.ToString().Split(',');    // 解析Tag中的参数
                
                mc = gntj[0]; // 功能名称
                ly = gntj[1]; // 功能来源
                bh = gntj[2]; // 功能编号
                xz = gntj[3]; // 执行权限
                lb = gntj[4]; // 功能类别
                
                if (ly == "系统功能") // 系统级功能
                {
                    X9Sys(mc); // 调用系统功能执行方法
                }
                else // 业务功能
                {
                    X9gn(mc, ly, bh, xz, null, null); // 调用业务功能执行方法
                }
            }
            catch (Exception ex)
            {
                MsgExShow("执行功能", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 运行功能定义
        /// 打开指定类型的功能定义窗口(用于设计模式)
        /// </summary>
        /// <param name="gnly">功能类别(如:查询输入、单据输入等)</param>
        private void RunGndy(string gnly)
        {
            try
            {
                // 检查功能定义窗口是否已经打开(避免重复打开)
                foreach (Form opfm in Application.OpenForms)
                {
                    if (opfm.Name == "rf0gndy")
                    {
                        if (opfm.Text == gnly + "功能定义")
                        {
                            // 如果已打开,则激活并前置该窗口
                            opfm.WindowState = FormWindowState.Normal;
                            opfm.Activate();
                            return; // 直接返回,不再创建新窗口
                        }
                    }
                }
                
                // 创建新的功能定义窗口
                FmGndy rf = new FmGndy
                {
                    dygnly = gnly,              // 功能类别
                    fname = gnly + "功能定义"   // 窗口标题
                };
                rf.prfm = this.Text; // 父窗口标题
                rf.Show(); // 以非模态方式显示
            }
            catch (Exception ex)
            {
                MsgExShow("执行" + gnly + "功能定义", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 运行模板设计
        /// 打开打印模板设计窗口(系统功能之一)
        /// </summary>
        private void RunMbsj()
        {
            try
            {
                // 检查模板设计窗口是否已经打开
                foreach (Form opfm in Application.OpenForms)
                {
                    if (opfm.Name == "KcRep")
                    {
                        opfm.WindowState = FormWindowState.Normal;
                        opfm.Activate();
                        return;
                    }
                }
                
                // 创建新的打印模板设计窗口
                FmDymb rfrep = new FmDymb();
                rfrep.Name = "KcRep";
                rfrep.Text = "打印模板设计";
                rfrep.Show(); // 以非模态方式显示
            }
            catch (Exception ex)
            {
                MsgExShow("执行模板设计功能", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 保存窗口设置
        /// 在退出或需要保存状态时调用,保存所有窗口状态到设置中
        /// 保存内容:窗口位置大小、分割器位置、选中的标签页、网格列宽等
        /// </summary>
        private void SaveFmSet()
        {
            try
            {
                // 1. 保存主窗口设置(7个参数)
                // 格式:Top,Left,Width,Height,SplitterPosition,SelectedTabPageIndex,WindowState
                fmset = this.Top.ToString().Trim() + "," + 
                        this.Left.ToString().Trim() + "," + 
                        this.Width.ToString().Trim() + "," +
                        this.Height.ToString().Trim() + "," + 
                        Sp1.SplitterPosition.ToString().Trim() + "," +
                        GNTab.SelectedTabPageIndex.ToString().Trim() + "," + 
                        Convert.ToInt32(this.WindowState).ToString();
                FmSave("主窗口", fmset);
                
                // 2. 保存任务网格列宽和行高
                if (rwgv != null && rwgv.RowCount > 0)
                {
                    fmset = rwgv.VisibleColumns[0].Width.ToString(); // 第一列宽度
                    for (int c = 1; c < rwgv.VisibleColumns.Count; c++)
                    {
                        if (rwgv.VisibleColumns[c].Visible)
                        {
                            fmset += "," + rwgv.VisibleColumns[c].Width.ToString().Trim(); // 可见列宽度
                        }
                        else
                        {
                            fmset += ",0"; // 不可见列宽度为0
                        }
                    }
                    FmSave("任务表格列宽行高", fmset + "," + rwgv.RowHeight.ToString()); // 最后添加行高
                }
                
                // 3. 保存状态网格列宽和行高(逻辑类似)
                if (ztgv != null && ztgv.RowCount > 0)
                {
                    fmset = ztgv.VisibleColumns[0].Width.ToString();
                    for (int c = 1; c < ztgv.VisibleColumns.Count; c++)
                    {
                        if (ztgv.VisibleColumns[c].Visible)
                        {
                            fmset += "," + ztgv.VisibleColumns[c].Width.ToString().Trim();
                        }
                        else
                        {
                            fmset += ",0";
                        }
                    }
                    FmSave("状态表格列宽行高", fmset + "," + ztgv.RowHeight.ToString());
                }
                
                // 4. 保存各功能面板的展开状态
                GetZkMk(ywlc); // 业务处理面板
                GetZkMk(xxlc); // 信息查询面板
                GetZkMk(jclc); // 基础资料面板
            }
            catch (Exception ex)
            {
                MsgExShow("保存窗口参数", ex.Message, ex.Source, ex.StackTrace);
            }
        }

        /// <summary>
        /// 业务日期变更事件
        /// 处理状态栏中业务日期的变更,支持手动和自动两种模式
        /// </summary>
        private void TsYwrq_EditValueChanged(object sender, EventArgs e)
        {
            // 如果启用手动业务日期模式
            if (pGDRQ)
            {
                string nrq = $"{Tsywrq.EditValue:yyyy-MM-dd}"; // 格式化日期
                
                // 验证日期不能超过当前业务期间
                if ((nrq.Substring(0, 4) + nrq.Substring(5, 2)).CompareTo(pYWQJ.Substring(0, 4) + pYWQJ.Substring(4, 2)) > 0)
                {
                    // 如果超过,重置为业务期间的第一天
                    Tsywrq.EditValue = Convert.ToDateTime(pYWQJ.Substring(0, 4) + "-" + pYWQJ.Substring(4, 2) + "-01");
                }
                
                // 保存手动业务日期到参数表
                SetZfcs("手动业务日期", $"{Tsywrq.EditValue:yyyy-MM-dd}");
                if (pDTCS.DataSet.HasChanges())
                {
                    KcDb.GetDtSaven("x9_ztcs", pDTCS.GetChanges());
                    pDTCS.AcceptChanges();
                }
                
                Tsywrq.Caption = "手动业务日期"; // 更新显示文本
                pYWRQ = (DateTime)Tsywrq.EditValue; // 更新全局变量
                Tsywrq.Edit.ReadOnly = false; // 允许编辑
            }
            else // 自动模式(使用系统当前日期)
            {
                Tsywrq.Caption = "实时业务日期"; // 更新显示文本
                pYWRQ = DateTime.Now; // 使用当前日期
                Tsywrq.EditValue = DateTime.Now; // 更新控件值
                Tsywrq.Edit.ReadOnly = true; // 禁止编辑
            }
        }

        /// <summary>
        /// 执行系统功能
        /// 根据功能名称调用相应的系统级功能
        /// </summary>
        /// <param name="mc">功能名称</param>
        private void X9Sys(string mc)
        {
            switch (mc)
            {
                case "打印模板设计":
                    RunMbsj(); // 打开打印模板设计窗口
                    break;
                case "电子表格数据交换":
                    FmEXCEL fjh = new FmEXCEL(); // 创建Excel数据交换窗口
                    fjh.ShowDialog(this);        // 模态显示
                    fjh = null;                  // 释放引用
                    break;
                case "数据字典条件编辑":
                    FmSjzdWh fzd = new FmSjzdWh(); // 创建数据字典维护窗口
                    fzd.ShowDialog(this);          // 模态显示
                    fzd = null;                    // 释放引用
                    break;
                // 可以继续添加其他系统功能...
            }
        }
    }
}

六、窗体功能代码说明

(一)概述

FmMain.cs 是“看潮ERP”系统的主窗口类,作为整个ERP系统的核心容器和总控制台,继承自DevExpress的RibbonForm,提供带功能区的高级窗口界面。该窗体负责系统初始化、用户权限管理、功能菜单加载、任务处理等核心功能。

(二)主要功能

1. 窗体初始化与启动

  • 构造函数 FmMain():初始化窗体组件并绑定所有事件处理器。
  • 窗口加载事件 Form_Load():系统初始化入口,执行环境检查、数据库连接、权限加载、界面构建等操作。
  • 主初始化方法 LoadForm():完成所有启动时必要的加载,包括目录创建、参数读取、图标加载、权限验证等。

2. 用户界面管理

  • 动态功能菜单加载 (MyGn 方法):根据用户权限动态生成左侧导航面板(基础资料/信息查询/业务处理)。
  • 任务列表显示 (LoadRwgv 方法):加载并显示当前用户的待办任务列表,支持任务操作按钮。
  • 皮肤/主题设置 (BarSKIN_ItemClick):允许用户更改界面主题。
  • Ribbon功能区管理:提供分类目录、功能定义、数据输入、业务处理等功能入口。

3. 权限与安全控制

  • 用户权限加载:从数据库读取用户角色和功能权限。
  • 授权模块过滤:只显示用户有权限访问的功能模块。
  • 密码安全提示:检测用户是否设置登录密码,未设置则强制提示。
  • 任务权限验证:执行任务时验证当前用户是否在申请人员列表中。

4. 数据管理

  • 数据库连接管理 (BarSJLJ_ItemClick):提供数据库重新连接功能。
  • 账套参数管理:加载和保存系统参数设置。
  • 配置文件管理:窗口状态、列宽设置等参数的保存和读取。
  • 文件目录管理:创建和维护系统所需的各种目录结构。

5. 任务与工作流处理

  • 任务列表加载与刷新 (LoadRwgv, Reloadrw):从数据库读取任务并动态配置网格列。
  • 任务链接按钮处理 (Ljcx_Buttonclick):处理任务列表中的操作按钮点击,执行相应的任务处理功能。
  • 任务状态跟踪:标记任务完成状态,更新任务列表。

6. 系统工具与维护

  • 功能定义管理 (RunGndy):在设计模式下打开各类功能定义界面。
  • 打印模板设计 (RunMbsj):打开打印模板设计窗口。
  • 数据字典配置 (Gdlomyrw):动态配置网格视图列,支持多种编辑器类型。
  • 异常日志管理:设计模式下提供异常日志清理功能。

(三)核心数据结构

窗口变量

public static GridView rwgv;           // “我的任务”表格视图
public static GridView ztgv;           // “系统状态”表格视图
public string cslj;                    // 系统配置和文件存储的根路径
public DataTable dtgntp;               // 功能模块图标数据表
public string fmset;                   // 窗口设置信息字符串
public ImageCollection gnimage;        // 功能图标集合
public LayoutControl jclc, xxlc, ywlc; // 各功能面板的布局控件
public bool pquit;                     // 退出标志
public string sqmk;                    // 授权模块字符串

权限相关全局变量

public string pYHJS;      // 用户角色
public string pDQYH;      // 当前用户
public DataTable pDTQX;   // 用户权限数据表
public string pZTMC;      // 账套名称
public bool pSFSJ;        // 是否设计模式

(四)事件处理机制

1. 功能区按钮事件

  • 分类目录、功能列表、各类数据输入/查询/处理功能按钮
  • 系统工具:皮肤设置、数据库连接、文件下载等
  • 用户管理:密码修改、用户信息查看

2. 任务相关事件

  • 任务刷新按钮点击事件
  • 任务操作按钮点击事件
  • 任务网格右键菜单事件

3. 窗体生命周期事件

  • 窗口激活事件:刷新任务列表
  • 窗口关闭事件:保存设置并清理资源
  • 窗口加载事件:系统初始化

4. 数据变更事件

  • 业务日期变更事件
  • 打印机选择变更事件

(五)设计特点

1. 动态权限驱动界面

  • 根据用户角色动态生成功能菜单
  • 按钮状态和可见性基于权限控制
  • 模块化分组展示,支持展开/收起

2. 工作流任务集成

  • 任务列表与工作流引擎集成
  • 支持任务驱动式业务处理
  • 多角色协作的任务分配机制

3. 自适应界面设计

  • 支持多种屏幕分辨率
  • 可保存和恢复窗口布局
  • 皮肤/主题切换支持

4. 配置化管理

  • 窗口参数、列宽、布局状态可保存
  • 业务规则和参数集中管理
  • 支持设计模式和运行模式切换

(六)使用注意事项

初始化顺序

  1. 环境检查和目录创建
  2. 数据库连接和权限验证
  3. 参数加载和图标资源初始化
  4. 功能菜单动态生成
  5. 任务列表和状态信息加载

权限控制要点

  • 功能访问受用户角色控制
  • 任务操作需要验证申请人员权限
  • 部分系统功能需要管理员权限

异常处理

  • 关键操作都有try-catch异常处理
  • 异常信息记录和用户提示
  • 设计模式下提供异常日志清理

性能优化

  • 批量更新操作使用BeginUpdate/EndUpdate
  • 图片资源按需加载
  • 数据库连接及时关闭

(七)扩展性

新增功能模块

  1. 在数据库中添加功能定义
  2. 配置用户权限
  3. 添加相应的图标资源
  4. 系统会自动在对应分类中显示

自定义业务规则

  • 通过参数表配置业务规则
  • 支持公式计算和输入限制
  • 可扩展的报表和打印模板

集成第三方组件

  • 支持Excel数据交换
  • 可扩展的文件关联处理
  • 打印和报表功能基于标准组件

(八)相关文件

  • FmAbout.cs:关于窗口
  • FmSKIN.cs:皮肤设置窗口
  • FmYHMM.cs:用户密码修改窗口
  • FmYhxx.cs:用户信息查看窗口
  • Uf01Flml.cs:功能列表定义窗口
  • FmGndy.cs:功能定义窗口

全文总结

文章先以200字点明核心:基于角色与任务重新组织Ribbon、导航、工作区,实现权限级动态菜单与任务流集成;随后给出“摘要+关键词+AI助手”三行规范格式。正文分六章递进:一、通用设计原则强调统一导航、角色仪表盘、高频入口、即时反馈与响应式;二、项目实例展示FmMain窗体“上Ribbon-中Split-下状态栏”细节,指出信息过载、导航深、命名歧义、硬编码等痛点;三、四、五章用3000行C#设计器与业务代码详解布局、控件层次、事件链及初始化流程,覆盖权限表读取、图标缓存、任务网格自定义按钮、参数XML序列化、皮肤切换、打印机列表等实现;六章回顾代码要点与扩展策略。整体为开发者提供一套“可编译、可配置、可复用”的ERP主窗口模板,兼顾视觉专业度与后期维护成本。

(本课题全文完)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐