1. 细分工程师用户权限(扩展制程工程师和设备工程师)
2. 配方修复选空白配方列表时,新建按钮不可点击的问题
3. 新添加双击配方列表事件
已修改7个文件
192 ■■■■■ 文件已修改
SourceCode/Bond/Servo/PageRecipe.cpp 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.h 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/RecipeManager.cpp 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/RecipeManager.h 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/UserManager.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/UserManagerDlg.cpp 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.cpp
@@ -237,7 +237,8 @@
    ON_BN_CLICKED(IDC_BUTTON_DELETE, &CPageRecipe::OnBnClickedButtonDelete)
    ON_BN_CLICKED(IDC_BUTTON_DELETE_ALL, &CPageRecipe::OnBnClickedButtonDeleteAll)
    ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CPageRecipe::OnBnClickedButtonRefresh)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_PPID, &CPageRecipe::OnLvnItemChangedListPPID)
    ON_NOTIFY(NM_CLICK, IDC_LIST_PPID, &CPageRecipe::OnClickListPPID)
    ON_NOTIFY(NM_DBLCLK, IDC_LIST_PPID, &CPageRecipe::OnDblclkListPPID)
    ON_CBN_SELCHANGE(IDC_COMBO_EQUIPMENT, &CPageRecipe::OnCbnSelchangeComboEquipment)
END_MESSAGE_MAP()
@@ -575,19 +576,48 @@
    }
}
void CPageRecipe::OnLvnItemChangedListPPID(NMHDR* pNMHDR, LRESULT* pResult)
void CPageRecipe::OnClickListPPID(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    *pResult = 0;
    CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
    int nEqSel = pComboBox->GetCurSel();
    int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd());
    if (pComboBox == nullptr) {
        return;
    }
    GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(/*nEqSel == 0 &&*/ selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    int nItem = pNMItemActivate->iItem;
    int nEqSel = pComboBox->GetCurSel();
    GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0);
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nItem > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && nItem > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && nItem > 0);
}
void CPageRecipe::OnDblclkListPPID(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    *pResult = 0;
    int nItem = pNMItemActivate->iItem;
    if (nItem < 0) {
        return;
    }
    CString strText = m_listPPID.GetItemText(nItem, 2);
    CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
    int nEqSel = pComboBox->GetCurSel();
    if (nEqSel == CB_ERR) {
        return;
    }
    SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nEqSel);
    if (pEq == nullptr) {
        return;
    }
}
void CPageRecipe::OnCbnSelchangeComboEquipment()
SourceCode/Bond/Servo/PageRecipe.h
@@ -37,7 +37,8 @@
    afx_msg void OnBnClickedButtonDelete();
    afx_msg void OnBnClickedButtonDeleteAll();
    afx_msg void OnBnClickedButtonRefresh();
    afx_msg void OnLvnItemChangedListPPID(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnClickListPPID(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDblclkListPPID(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnCbnSelchangeComboEquipment();
    DECLARE_MESSAGE_MAP()
SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp
SourceCode/Bond/Servo/RecipeManager.cpp
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "RecipeManager.h"
#include <sstream>
#include <iomanip>
@@ -35,7 +35,7 @@
        return false;
    }
    // 启用 SQLite 的外键约束支持
    // 启用 SQLite 的外键约束支持
    if (!m_pDB->executeQuery("PRAGMA foreign_keys = ON;")) {
        std::cerr << "Failed to enable foreign keys." << std::endl;
        return false;
@@ -116,7 +116,7 @@
    std::lock_guard<std::recursive_mutex> lock(m_mutex);
    // 开始事务
    // 开始事务
    m_pDB->executeQuery("BEGIN TRANSACTION;");
    std::ostringstream oss;
@@ -148,7 +148,7 @@
        }
    }
    // 提交事务
    // 提交事务
    m_pDB->executeQuery("COMMIT;");
    return true;
}
@@ -159,13 +159,13 @@
        return false;
    }
    // 检查 ppid 是否存在
    // 检查 ppid 是否存在
    if (!ppidExists(ppid)) {
        std::cerr << "[addRecipeDevice] PPID does not exist: " << ppid << std::endl;
        return false;
    }
    // 插入设备记录
    // 插入设备记录
    std::ostringstream oss;
    oss << "INSERT OR REPLACE INTO recipe_devices (ppid, device_id, device_name, recipe_id, recipe_name) VALUES ('"
        << ppid << "', "
@@ -423,7 +423,7 @@
    std::lock_guard<std::recursive_mutex> lock(m_mutex);
    // 检查是否已经存在相同的 newPPID
    // 检查是否已经存在相同的 newPPID
    auto check = m_pDB->fetchResults("SELECT COUNT(*) FROM recipes WHERE ppid = '" + newPPID + "';");
    if (!check.empty() && !check[0].empty() && check[0][0] != "0") {
        std::cerr << "[updatePPID] New PPID already exists: " << newPPID << std::endl;
@@ -579,13 +579,13 @@
    addRecipe(recipe);
    addDeviceRecipe("Bonder1", 101, "标准工艺");
    addDeviceRecipe("Bonder1", 102, "改良工艺");
    addDeviceRecipe("Bonder1", 103, "高速模式");
    addDeviceRecipe("Bonder1", 101, "标准工艺");
    addDeviceRecipe("Bonder1", 102, "改良工艺");
    addDeviceRecipe("Bonder1", 103, "高速模式");
    addDeviceRecipe("Bonder2", 101, "标准工艺");
    addDeviceRecipe("Bonder2", 102, "改良工艺");
    addDeviceRecipe("Bonder2", 103, "高速模式");
    addDeviceRecipe("Bonder2", 101, "标准工艺");
    addDeviceRecipe("Bonder2", 102, "改良工艺");
    addDeviceRecipe("Bonder2", 103, "高速模式");
}
bool RecipeManager::readRecipeFile(const std::string& filename) {
SourceCode/Bond/Servo/RecipeManager.h
@@ -1,4 +1,4 @@
#ifndef RECIPE_MANAGER_H
#ifndef RECIPE_MANAGER_H
#define RECIPE_MANAGER_H
#include <string>
@@ -7,94 +7,94 @@
#include <unordered_map>
#include "Database.h"
// 单个设备配方映射信息
// 单个设备配方映射信息
struct DeviceRecipe {
    int nDeviceID;               // 设备ID
    int nRecipeID;               // 子配方ID
    std::string strDeviceName;   // 设备名称
    std::string strRecipeName;   // 子配方名称
    int nDeviceID;               // 设备ID
    int nRecipeID;               // 子配方ID
    std::string strDeviceName;   // 设备名称
    std::string strRecipeName;   // 子配方名称
};
// 配方信息
// 配方信息
struct RecipeInfo {
    std::string strPPID;         // 配方ID
    std::string strDescription;  // 配方描述
    std::string strCreateTime;   // 创建时间
    std::vector<DeviceRecipe> vecDeviceList;  // 关联的设备信息列表
    std::string strPPID;         // 配方ID
    std::string strDescription;  // 配方描述
    std::string strCreateTime;   // 创建时间
    std::vector<DeviceRecipe> vecDeviceList;  // 关联的设备信息列表
};
using RecipeMap = std::unordered_map<std::string, RecipeInfo>; // 按 PPID 映射的配方表
using RecipeMap = std::unordered_map<std::string, RecipeInfo>; // 按 PPID 映射的配方表
class RecipeManager {
public:
    // 获取单例
    // 获取单例
    static RecipeManager& getInstance();
    // 初始化配方数据库
    // 初始化配方数据库
    bool initRecipeTable();
    // 销毁表或关闭连接
    // 销毁表或关闭连接
    void termRecipeTable();
    bool destroyRecipeTable();
    // 检查 PPID 是否存在
    // 检查 PPID 是否存在
    bool ppidExists(const std::string& ppid);
    // 检查设备是否存在于指定 PPID 的配方中
    // 检查设备是否存在于指定 PPID 的配方中
    bool deviceExists(const std::string& ppid, int nDeviceID);
    // 添加一个配方及其设备映射
    // 添加一个配方及其设备映射
    bool addRecipe(const RecipeInfo& recipe);
    // 添加设备到指定配方
    // 添加设备到指定配方
    bool addRecipeDevice(const std::string& ppid, const DeviceRecipe& device);
    // 删除指定 PPID 的设备配方
    // 删除指定 PPID 的设备配方
    bool deleteRecipeDeviceByID(const std::string& ppid, int nDeviceID);
    // 删除指定 PPID 的设备配方(通过设备名称)
    // 删除指定 PPID 的设备配方(通过设备名称)
    bool deleteRecipeDeviceByName(const std::string& ppid, const std::string& strDeviceName);
    // 查询所有配方
    // 查询所有配方
    std::vector<RecipeInfo> getAllRecipes();
    // 根据 PPID 或描述查询配方
    // 根据 PPID 或描述查询配方
    std::vector<RecipeInfo> getRecipesByKeyword(const std::string& keyword);
    // 获取所有 PPID
    // 获取所有 PPID
    std::vector<std::string> getAllPPID() const;
    // 按 ID 查询 PPID
    // 按 ID 查询 PPID
    std::string getPPIDById(int nId);
    // 按 PPID 查询 ID
    // 按 PPID 查询 ID
    int getIdByPPID(const std::string& ppid);
    // 按 PPID 查询配方
    // 按 PPID 查询配方
    RecipeInfo getRecipeByPPID(const std::string& ppid);
    // 根据 PPID 和设备ID 获取设备配方ID
    // 根据 PPID 和设备ID 获取设备配方ID
    int getDeviceRecipeIDByID(const std::string& ppid, int nDeviceID);
    // 根据 PPID 和设备名称 获取设备配方ID
    // 根据 PPID 和设备名称 获取设备配方ID
    int getDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName);
    // 删除指定 PPID 的配方
    // 删除指定 PPID 的配方
    bool deleteRecipeByPPID(const std::string& ppid);
    // 更新指定 PPID 的配方
    // 更新指定 PPID 的配方
    bool updateRecipe(const RecipeInfo& recipe);
    // 更新 PPID(通过旧 PPID 和新 PPID)
    // 更新 PPID(通过旧 PPID 和新 PPID)
    bool updatePPID(const std::string& oldPPID, const std::string& newPPID);
    // 更新配方描述(通过 PPID)
    // 更新配方描述(通过 PPID)
    bool updateDescription(const std::string& ppid, const std::string& newDescription);
    // 更新设备配方ID(通过 PPID 和设备ID)
    // 更新设备配方ID(通过 PPID 和设备ID)
    bool updateDeviceRecipeIDByID(const std::string& ppid, int nDeviceID, int nNewRecipeID);
    // 更新设备配方ID(通过 PPID 和设备名称)
    // 更新设备配方ID(通过 PPID 和设备名称)
    bool updateDeviceRecipeIDByName(const std::string& ppid, const std::string& strDeviceName, int nNewRecipeID);
    bool addDeviceRecipe(const std::string& deviceName, int nRecipeID, const std::string& strRecipeName);
@@ -103,13 +103,13 @@
    bool deleteDeviceRecipe(const std::string& deviceName, int nRecipeID);
    std::vector<std::pair<int, std::string>> getDeviceRecipes(const std::string& deviceName);
    // 模拟插入数据(测试用)
    // 模拟插入数据(测试用)
    void insertMockData();
    // 读取配方文件(CSV 或 JSON)
    // 读取配方文件(CSV 或 JSON)
    bool readRecipeFile(const std::string& filename);
    // 保存配方到文件
    // 保存配方到文件
    bool saveRecipeFile(const std::string& filename);
private:
SourceCode/Bond/Servo/UserManager.h
@@ -9,9 +9,11 @@
// 用户角色定义
enum class UserRole {
    SuperAdmin = 0,     // 超级管理员
    Engineer,           // 工程师
    Operator            // 操作员
    SuperAdmin = 0,   // 超级管理员:系统最高权限,管理所有用户和权限
    ProcessEngineer,  // 制程工程师:负责工艺制定与优化
    EquipmentEngineer,// 设备工程师:负责设备维护与技术支持
    Operator,         // 操作员:执行日常生产操作
    Unknown           // 未知角色:默认或未识别的角色
};
// 用户管理类,采用单例模式
SourceCode/Bond/Servo/UserManagerDlg.cpp
@@ -88,9 +88,10 @@
    m_gridUserManager.ExpandLastColumn();                // 最后一列填充网格
    m_mapRoleDescriptions.clear();
    m_mapRoleDescriptions.emplace(_T("管理员"), _T("管理所有用户,分配权限"));
    m_mapRoleDescriptions.emplace(_T("工程师"), _T("维护系统,解决技术问题"));
    m_mapRoleDescriptions.emplace(_T("操作员"), _T("执行日常操作任务"));
    m_mapRoleDescriptions.emplace(_T("管理员"), _T("管理所有用户账户,分配和调整权限,负责系统安全与整体运行"));
    m_mapRoleDescriptions.emplace(_T("制程工程师"), _T("负责生产工艺的制定、优化与改进,确保工艺稳定和良率提升"));
    m_mapRoleDescriptions.emplace(_T("设备工程师"), _T("维护和保养设备,处理故障,保障设备稳定运行,参与技术升级"));
    m_mapRoleDescriptions.emplace(_T("操作员"), _T("按照标准流程执行日常操作任务,监控生产状况,及时反馈异常"));
    FillUserManager();
}
@@ -134,7 +135,8 @@
    CStringArray permissions;
    permissions.Add(_T("管理员"));
    permissions.Add(_T("工程师"));
    permissions.Add(_T("制程工程师"));
    permissions.Add(_T("设备工程师"));
    permissions.Add(_T("操作员"));
    int nCols = m_gridUserManager.GetColumnCount();
@@ -149,13 +151,12 @@
            pCell->SetOptions(permissions);
            pCell->SetStyle(CBS_DROPDOWNLIST);
            CString cstrRole = m_gridUserManager.GetItemText(i, 3);
            int nRole = _ttoi(cstrRole);
            if (nRole < 0 || nRole > 2) {
            int nRole = _ttoi(m_gridUserManager.GetItemText(i, 3));
            if (nRole < 0 || nRole > 3) {
                CString cstrMessage;
                cstrMessage.Format(_T("用户 [%s],权限异常!将设置成操作员!"), m_gridUserManager.GetItemText(i, 1));
                AfxMessageBox(cstrMessage);
                nRole = 2;
                nRole = 3;
            }
            m_gridUserManager.SetItemText(i, 3, permissions.GetAt(nRole));
@@ -237,7 +238,8 @@
    // 第四列设置(权限列)为下拉框
    CStringArray permissions;
    permissions.Add(_T("管理员"));
    permissions.Add(_T("工程师"));
    permissions.Add(_T("制程工程师"));
    permissions.Add(_T("设备工程师"));
    permissions.Add(_T("操作员"));
    if (pGridCtrl->SetCellType(newRowIndex, 3, RUNTIME_CLASS(CGridCellCombo))) {
@@ -443,7 +445,8 @@
        CStringArray permissions;
        permissions.Add(_T("管理员"));
        permissions.Add(_T("工程师"));
        permissions.Add(_T("制程工程师"));
        permissions.Add(_T("设备工程师"));
        permissions.Add(_T("操作员"));
        if (m_gridUserManager.SetCellType(row, 3, RUNTIME_CLASS(CGridCellCombo))) {
@@ -527,12 +530,14 @@
            if (j == 3) {
                if (cellText == _T("管理员"))
                    cellString = "0";
                else if (cellText == _T("工程师"))
                else if (cellText == _T("制程工程师"))
                    cellString = "1";
                else if (cellText == _T("设备工程师"))
                    cellString = "2";
                else if (cellText == _T("操作员"))
                    cellString = "2";
                    cellString = "3";
                else
                    cellString = "2";
                    cellString = "3";
            }
            rowData.push_back(cellString);