<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>License 分发管理</title> <style> /* 保持样式不变 */ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background-color: #f8f8f8; margin: 0; padding: 0; display: flex; } header { display: flex; justify-content: space-between; align-items: center; padding: 20px; background-color: #1169ff; color: white; width: 100%; margin: 0; /* 移除上下左右的空隙 */ box-sizing: border-box; /* 确保padding不会影响元素的宽度 */ border: 4px solid #1169ff; /* 确保红框颜色填满 */ border-width: 4px 0 4px 0; /* 只显示上下的红框颜色 */ border-radius: 10px; /* 设置圆角 */ } h1 { font-size: 24px; font-weight: 600; margin: 0; } .CaptureLicenseOnce-button { background-color: white; color: #007aff; border: 2px solid #007aff; padding: 10px 20px; border-radius: 10px; cursor: pointer; font-size: 16px; font-weight: 500; box-shadow: none; transition: background-color 0.3s, color 0.3s; float: right; /* 将按钮移动到左侧 */ } .CaptureLicenseOnce-button:hover { background-color: #0eb3ff; color: white; } /* 扁平风格的选择框 */ .flat-select { background-color: transparent; /* 背景色透明 */ border: 1px solid #007aff; /* 边框颜色与按钮一致 */ border-radius: 15px; /* 圆角边框 */ padding: 5px 10px; /* 内边距 */ font-size: 16px; /* 字体大小 */ color: #007aff; /* 文字颜色 */ outline: none; /* 移除默认的焦点样式 */ appearance: none; /* 移除默认的下拉箭头样式 */ -webkit-appearance: none; /* 对部分浏览器的兼容性处理 */ -moz-appearance: none; /* 对部分浏览器的兼容性处理 */ cursor: pointer; /* 鼠标指针样式 */ margin-left: 10px; /* 添加左边距,使选择框与前面的元素有些距离 */ box-shadow: none; /* 移除阴影效果 */ transition: background-color 0.3s, color 0.3s; /* 添加过渡效果 */ } /* 选择框在悬停时的效果 */ .flat-select:hover { background-color: #007aff; /* 背景色变为蓝色 */ color: white; /* 文字颜色变为白色 */ } /* 选择框在聚焦时的效果 */ .flat-select:focus { background-color: #e0f7ff; /* 聚焦时的背景颜色 */ border-color: #0056b3; /* 聚焦时的边框颜色 */ } /* 添加下拉箭头的样式 */ .flat-select::after { content: '▼'; /* 使用字符作为下拉箭头 */ position: absolute; right: 10px; pointer-events: none; /* 确保下拉箭头不会遮挡选择框 */ } /* 扁平圆角风格的按钮样式 */ .flat-rounded-button { background-color: white; color: #007aff; border: 2px solid #007aff; padding: 10px 20px; border-radius: 15px; cursor: pointer; font-size: 16px; font-weight: 500; box-shadow: none; /* 移除阴影效果 */ transition: background-color 0.3s, color 0.3s; margin: 5px; /* 添加按钮之间的间距 */ } /* 悬停时的效果 */ .flat-rounded-button:hover { background-color: #0eb3ff; color: white; } /*lic 展示页 主行展开后变化*/ .expanded-row { background-color: #0eb3ff; /* 展开时的背景颜色 */ border-color: #04aa9c; /* 展开时的边框颜色 */ border-width: 4px; /* 边框宽度 */ border-radius: 35px; /* 边框圆角 */ transition: all 0.2s ease; /* 添加过渡效果 */ } /*苹果风格模态框*/ .apple-modal-content { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; padding: 20px; border-radius: 12px; background-color: white; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); margin-bottom: 20px; min-width: 250px; /* 添加最小宽度 */ } .apple-modal-title { font-size: 24px; font-weight: 600; color: #333; margin-bottom: 10px; } .apple-modal-subtitle { font-size: 20px; font-weight: 500; color: #555; margin-top: 20px; margin-bottom: 10px; } /* 苹果风格的文字样式 */ .apple-modal-text { font-size: 16px; color: #555; line-height: 1.6; margin-bottom: 10px; } /* 强调部分 */ .apple-modal-text strong { color: #333; } /* 苹果风格的模态框关闭按钮 */ .apple-close { color: #aaa; font-size: 24px; /* 调整字体大小 */ font-weight: bold; cursor: pointer; transition: color 0.3s; } .apple-close:hover { color: black; } /* 苹果风格的退出按钮 */ .apple-logout-button { background-color: #007aff; /* 苹果风格的蓝色 */ color: white; border: none; padding: 8px 16px; /* 减小内边距,使按钮更小 */ border-radius: 10px; /* 圆角稍微减小 */ font-size: 14px; /* 调整字体大小 */ font-weight: 500; cursor: pointer; transition: background-color 0.3s, transform 0.3s; } .apple-logout-button:hover { background-color: #005bb5; /* 悬停时按钮颜色变深 */ transform: scale(1.05); /* 悬停时按钮略微放大 */ } .apple-logout-button:active { background-color: #003e7e; /* 点击时按钮颜色更深 */ transform: scale(0.98); /* 点击时按钮略微缩小 */ } .upload-button, .user-button { background-color: white; color: #007aff; border: none; padding: 10px 20px; border-radius: 10px; cursor: pointer; font-size: 16px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: background-color 0.3s; } .upload-button:hover, .user-button:hover { background-color: #f0f0f0; } .sidebar { width: 200px; background-color: #f1f1f1; padding: 20px; box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1); height: 100vh; transition: transform 0.3s ease; } .sidebar.hidden { transform: translateX(-100%); } .sidebar button { width: 100%; padding: 10px; margin-bottom: 10px; background-color: white; color: #007aff; border: none; border-radius: 10px; cursor: pointer; font-size: 16px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: background-color 0.3s; } .sidebar button:hover { background-color: #e0e0e0; } .content { flex-grow: 1; padding: 20px; transition: margin-left 0.3s ease; } .content.expanded { margin-left: -200px; } .toggle-sidebar { position: fixed; top: 50%; /* 垂直居中 */ transform: translateY(-50%); /* 调整为居中对齐 */ left: 0; /* 靠左对齐 */ background-color: #007aff; color: white; border: none; padding: 10px; cursor: pointer; border-radius: 0 10px 10px 0; /* 右侧圆角,左侧保持平直 */ width: 30px; /* 长条形箭头的宽度 */ height: 60px; /* 长条形箭头的高度 */ z-index: 1000; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; /* 添加动效 */ } .sidebar.hidden + .content .toggle-sidebar { left: 0; transform: translateX(0) translateY(-50%); } /* 按钮容器的样式 */ .button-container { display: inline-flex; /* 确保按钮在同一行 */ align-items: center; /* 垂直居中对齐 */ gap: 10px; /* 设置按钮之间的间距为10px,可以根据需要调整 */ } /* 统一按钮的样式 */ /* 通用按钮样式 */ .license-status-btn { display: inline-block; padding: 5px 15px; font-size: 14px; font-weight: bold; color: white; text-align: center; border-radius: 15px; /* 圆角样式 */ cursor: pointer; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */ transition: background-color 0.3s; border: none; /* 移除按钮边框 */ } /* 查看详情按钮的特定样式 */ .license-status-btn.view-details { background-color: #add8e6; /* 浅蓝色背景 */ color: white; } /* 下载lic按钮的特定样式 */ .license-status-btn.download-lic { background-color: #4CAF50; /* 绿色背景 */ color: white; } /* 分发按钮样式 */ .license-status-btn.distribute { background-color: #007bff; /* 蓝色背景 */ } .license-status-btn.distribute:hover { background-color: #0056b3; /* 悬停时的颜色 */ } /* 生成按钮样式 */ .license-status-btn.generate { background-color: #ffc107; /* 黄色背景 */ } .license-status-btn.generate:hover { background-color: #e0a800; /* 悬停时的颜色 */ } /* 默认状态下的箭头图标 */ .arrow-icon { width: 10px; height: 10px; border: solid #007aff; border-width: 0 3px 3px 0; display: inline-block; padding: 3px; transform: rotate(45deg); /* 初始方向向下 */ transition: transform 0.3s ease; /* 添加旋转过渡效果 */ cursor: pointer; } /* 当行展开时旋转箭头图标 */ .rotate-arrow { transform: rotate(-135deg); /* 旋转方向向上 */ } /*分发历史样式*/ #distributionHistoryModal .centered-modal-content { background-color: #ffffff; border: none; border-radius: 15px; padding: 20px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); text-align: center; width: 30%; /* 设置宽度为屏幕的80% */ max-width: 90%; /* 最大宽度设置为90%屏幕宽度 */ height: auto; /* 高度自适应内容 */ max-height: 80vh; /* 设置最大高度为屏幕的80% */ overflow-y: auto; /* 如果内容超出则添加垂直滚动条 */ overflow-x: hidden; /* 水平不出现滚动条 */ margin: 0 auto; /* 居中显示 */ } /* lic查看详细按钮样式 */ .license-status-btn.view-details { background-color: #add8e6; /* 浅蓝色背景 */ color: white; /* 白色文字 */ border: none; /* 移除按钮边框 */ padding: 8px 16px; /* 调整内边距,与“生成”按钮保持一致 */ border-radius: 20px; /* 调整圆角,确保形状一致 */ cursor: pointer; font-size: 14px; /* 调整字体大小,确保一致 */ font-weight: 500; /* 字体权重,确保一致 */ margin-left: 10px; /* 与其他按钮的间隔 */ transition: background-color 0.3s, color 0.3s; /* 添加过渡效果 */ } .license-status-btn.view-details:hover { background-color: #87ceeb; /* 悬停时颜色变深 */ } /* 表格样式 */ /* 表格容器 */ /* 表格容器 */ table { width: 100%; border-collapse: separate; border-spacing: 0 4px; /* 设置行间距为4px */ /* background-color: transparent; 使表格背景透明,突出行间距效果 */ margin: 20px 0; } th, td { padding: 15px 20px; /* 设置单元格内边距 */ text-align: left; font-size: 16px; /* background-color: white; 单元格背景色 */ } /* 鼠标悬停时改变边框颜色 */ tr:hover { background-color: #e6f7ff; /* 设置悬停时的背景颜色 */ border-color: #1169ff; /* 设置悬停时的边框颜色 */ border-width: 4px; /* 设置悬停时的边框大小 */ border-radius: 15px; /* 设置悬停时的圆角 */ } th { background-color: #f8f8f8; /* 表头背景色 */ font-weight: bold; color: #333; } td { color: #555; } /* 表格行样式 */ tr { background-color: white; /* 每行背景色 */ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); /* 设置阴影效果 */ border-radius: 10px; /* 设置每行的圆角 */ overflow: hidden; /* 确保圆角效果生效 */ border: 2px solid transparent; /* 默认边框为透明 */ transition: all 0.3s ease; /* 添加过渡效果 */ } /* 确保单元格也适应行的圆角 */ tr:first-child td:first-child { border-top-left-radius: 10px; } tr:first-child td:last-child { border-top-right-radius: 10px; } tr:last-child td:first-child { border-bottom-left-radius: 10px; } tr:last-child td:last-child { border-bottom-right-radius: 10px; } /*添加用户样式*/ .flat-rounded-input { width: calc(100% - 40px); /* 与其他输入框一致的宽度 */ padding: 15px 20px; /* 更大的内边距 */ font-size: 18px; /* 更大的字体 */ border: 2px solid #e0e0e0; /* 边框颜色 */ border-radius: 25px; /* 圆角边框 */ box-sizing: border-box; margin-bottom: 20px; background-color: #f8f8f8; /* 背景色 */ transition: border-color 0.3s, box-shadow 0.3s; /* 添加动画效果 */ } .flat-rounded-input:focus { border-color: #007aff; /* 聚焦时的边框颜色 */ box-shadow: 0 0 8px rgba(0, 122, 255, 0.2); /* 聚焦时的阴影效果 */ outline: none; /* 去掉默认的聚焦样式 */ } .flat-rounded-button { background-color: #007aff; color: white; border: none; padding: 15px 20px; border-radius: 25px; cursor: pointer; font-size: 18px; font-weight: bold; box-shadow: none; /* 移除阴影效果 */ transition: background-color 0.3s, color 0.3s; } .flat-rounded-button:hover { background-color: #005bb5; } .form-group { display: flex; align-items: center; margin-bottom: 15px; } .form-group label { flex: 0 0 80px; /* 固定标签宽度 */ text-align: right; margin-right: 10px; /* 标签与输入框之间的间距 */ } .form-group input { flex: 1; /* 输入框占据剩余空间 */ } /* 分页按钮样式 */ .pagination button { padding: 10px 20px; margin: 0 5px; cursor: pointer; border: none; border-radius: 15px; background-color: #007aff; color: white; font-size: 16px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: background-color 0.3s; } .pagination button:disabled { background-color: #b0c4de; cursor: not-allowed; } .pagination button:not(:disabled):hover { background-color: #005bb5; } .modal { display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0, 0, 0, 0.4); } .modal-content { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fefefe; padding: 20px; border: 1px solid #888; border-radius: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); max-width: 100%; max-height: 90%; overflow-y: auto; } /*修改license信息的样式*/ .modify-license-modal-content { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fefefe; padding: 50px; border: 1px solid #888; border-radius: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); width: 400px; height: 80%; /* 设置为你希望的高度 */ overflow-y: auto; text-align: center; } .modify-license-modal-content input[type="number"], .modify-license-modal-content input[type="date"], .modify-license-modal-content input[type="text"], .modify-license-modal-content input[type="email"], .modify-license-modal-content input[type="password"], .modify-license-modal-content textarea, .modify-license-modal-content select { width: calc(100% - 40px); padding: 15px 20px; /* 更大内边距 */ font-size: 18px; /* 更大字体 */ border: 2px solid #e0e0e0; /* 边框颜色 */ border-radius: 25px; /* 圆形边框 */ box-sizing: border-box; margin-bottom: 20px; background-color: #f8f8f8; /* 背景色更浅 */ transition: border-color 0.3s, box-shadow 0.3s; /* 添加动画效果 */ } .modify-license-modal-content input[type="number"]:focus, .modify-license-modal-content input[type="date"]:focus, .modify-license-modal-content input[type="text"]:focus, .modify-license-modal-content input[type="email"]:focus, .modify-license-modal-content input[type="password"]:focus, .modify-license-modal-content textarea:focus, .modify-license-modal-content select:focus { border-color: #007aff; /* 聚焦时的边框颜色 */ box-shadow: 0 0 8px rgba(0, 122, 255, 0.2); /* 聚焦时的阴影效果 */ outline: none; /* 去掉默认的聚焦样式 */ } .modify-license-modal-content button { width: 100%; padding: 15px 20px; font-size: 18px; font-weight: bold; color: white; background-color: #007aff; border: none; border-radius: 25px; cursor: pointer; transition: background-color 0.3s; } .modify-license-modal-content button:hover { background-color: #005bb5; /* 鼠标悬停时的颜色变化 */ } .modify-license-modal-content .close { color: #aaa; float: right; font-size: 30px; font-weight: bold; } .modify-license-modal-content .close:hover, .modify-license-modal-content .close:focus { color: black; text-decoration: none; cursor: pointer; } .modify-license-modal-content .extra-info { padding: 20px; background-color: white; border: 1px solid #ddd; border-radius: 10px; margin-top: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); line-height: 1.5; /* 增加行高,保证字段间距 */ } .modal-content input[type="number"] { width: calc(100% - 40px); padding: 15px 20px; /* 与其他输入框的内边距一致 */ font-size: 18px; /* 与其他输入框的字体大小一致 */ border: 2px solid #e0e0e0; /* 与其他输入框的边框颜色一致 */ border-radius: 25px; /* 与其他输入框的圆角一致 */ box-sizing: border-box; margin-bottom: 20px; background-color: #f8f8f8; /* 与其他输入框的背景色一致 */ transition: border-color 0.3s, box-shadow 0.3s; /* 与其他输入框的过渡效果一致 */ } .modal-content input[type="number"]:focus { border-color: #007aff; /* 与其他输入框获得焦点时的边框颜色一致 */ box-shadow: 0 0 8px rgba(0, 122, 255, 0.2); /* 与其他输入框获得焦点时的阴影效果一致 */ outline: none; /* 移除默认的焦点轮廓 */ } .modal-content input[type="date"] { width: calc(100% - 40px); padding: 15px 20px; /* 与其他输入框的内边距一致 */ font-size: 18px; /* 与其他输入框的字体大小一致 */ border: 2px solid #e0e0e0; /* 与其他输入框的边框颜色一致 */ border-radius: 25px; /* 与其他输入框的圆角一致 */ box-sizing: border-box; margin-bottom: 20px; background-color: #f8f8f8; /* 与其他输入框的背景色一致 */ transition: border-color 0.3s, box-shadow 0.3s; /* 与其他输入框的过渡效果一致 */ } .modal-content input[type="date"]:focus { border-color: #007aff; /* 与其他输入框获得焦点时的边框颜色一致 */ box-shadow: 0 0 8px rgba(0, 122, 255, 0.2); /* 与其他输入框获得焦点时的阴影效果一致 */ outline: none; /* 移除默认的焦点轮廓 */ } /* 输入框样式 */ .modal-content input[type="text"], .modal-content input[type="email"], .modal-content input[type="password"], .modal-content textarea, .modal-content select { width: calc(100% - 40px); padding: 15px 20px; /* 更大内边距 */ font-size: 18px; /* 更大字体 */ border: 2px solid #e0e0e0; /* 边框颜色 */ border-radius: 25px; /* 圆形边框 */ box-sizing: border-box; margin-bottom: 20px; background-color: #f8f8f8; /* 背景色更浅 */ transition: border-color 0.3s, box-shadow 0.3s; /* 添加动画效果 */ } /* 输入框聚焦时的样式 */ .modal-content input[type="text"]:focus, .modal-content input[type="email"]:focus, .modal-content input[type="password"]:focus, .modal-content textarea:focus, .modal-content select:focus { border-color: #007aff; /* 聚焦时的边框颜色 */ box-shadow: 0 0 8px rgba(0, 122, 255, 0.2); /* 聚焦时的阴影效果 */ outline: none; /* 去掉默认的聚焦样式 */ } /* 按钮样式 */ .modal-content button { width: 100%; padding: 15px 20px; font-size: 18px; font-weight: bold; color: white; background-color: #007aff; border: none; border-radius: 25px; cursor: pointer; transition: background-color 0.3s; } .modal-content button:hover { background-color: #005bb5; /* 鼠标悬停时的颜色变化 */ } .close { color: #aaa; float: right; font-size: 30px; font-weight: bold; text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); } .close:hover { color: #000; /* 悬停时颜色变为黑色 */ transform: scale(1.1); /* 悬停时稍微放大 */ } .close:focus { color: black; text-decoration: none; cursor: pointer; } .extra-info { padding: 20px; background-color: white; border: 1px solid #ddd; border-radius: 10px; margin-top: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); line-height: 1.5; /* 增加行高,保证字段间距 */ } .extra-info p { margin: 10px 0; /* 每个字段的间距 */ word-wrap: break-word; /* 允许在单词内断行 */ word-break: break-all; /* 允许在任何字符处断行 */ white-space: pre-wrap; /* 保持空格和换行符 */ border-bottom: 1px solid #f0f0f0; /* 每个字段下方加上细线 */ padding-bottom: 8px; /* 加大下方内边距 */ } /* 修改运维邮箱和销售邮箱的勾选框样式 */ #emailInputs { display: flex; flex-direction: column; /* 确保每一行都垂直排列 */ gap: 10px; /* 增加每行之间的间距 */ } #emailInputs div { display: flex; align-items: center; /* 垂直居中 */ } #emailInputs input[type="checkbox"] { appearance: none; background-color: #fff; margin: 0; font: inherit; color: #007aff; width: 1.15em; height: 1.15em; border: 0.15em solid #007aff; border-radius: 0.15em; transform: translateY(-0.075em); display: grid; place-content: center; } #emailInputs input[type="checkbox"]::before { content: ""; width: 0.65em; height: 0.65em; clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 22%, 80% 0%, 43% 62%); transform: scale(0); transform-origin: bottom left; transition: transform 0.15s ease-in-out; box-shadow: inset 1em 1em #007aff; /* 使用淡蓝色与主题颜色匹配 */ background-color: CanvasText; } #emailInputs input[type="checkbox"]:checked::before { transform: scale(1); } .user-info { position: absolute; width: 300px; background-color: white; padding: 20px; border: 1px solid #ddd; border-radius: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); display: none; } .user-info .close { position: absolute; top: 10px; right: 10px; color: #aaa; font-size: 24px; font-weight: bold; cursor: pointer; } .user-info .close:hover, .user-info .close:focus { color: black; text-decoration: none; } .centered-modal-content { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fefefe; padding: 50px; border: 1px solid #888; border-radius: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); width: 400px; height: 400px; overflow-y: auto; text-align: center; } .ios-button { width: 100%; padding: 10px; margin: 0; border: none; border-radius: 0; font-size: 16px; font-weight: 600; color: #007aff; background-color: transparent; text-align: center; cursor: pointer; transition: background-color 0.3s; } .ios-button:active { background-color: rgba(0, 122, 255, 0.1); } .email-modal-label { font-size: 18px; margin-bottom: 10px; display: block; } .email-modal-input { width: calc(100% - 20px); padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 5px; margin-bottom: 10px; } .email-modal .modal-content { width: 90%; /* 修改宽度 */ max-width: 600px; /* 最大宽度 */ height: auto; /* 自适应高度 */ max-height: 80%; /* 最大高度,防止内容溢出屏幕 */ overflow-y: auto; /* 添加垂直滚动条,如果内容超出 */ } .add-email-button { display: block; width: 100%; padding: 10px 20px; margin-bottom: 10px; background-color: #007aff; color: white; border: none; text-align: center; font-size: 16px; cursor: pointer; border-radius: 5px; transition: background-color 0.3s; } .add-email-button:hover { background-color: #005bb5; } .action-modal-content { display: flex; flex-direction: column; align-items: flex-start; } .action-modal-content button { width: auto; padding: 10px 20px; margin: 5px 0; background-color: white; color: black; border: none; text-align: left; font-size: 16px; cursor: pointer; border-radius: 5px; transition: background-color 0.3s; } .action-modal-content button:hover { background-color: #f0f0f0; } .sort-button { background-color: transparent; border: none; color: #007aff; font-size: 16px; cursor: pointer; padding: 5px 10px; border-radius: 15px; transition: background-color 0.3s; } .sort-button:hover { background-color: rgba(0, 122, 255, 0.1); } #confirmGenerateModal .centered-modal-content { background-color: #ffffff; border: none; border-radius: 15px; padding: 20px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); text-align: center; } #confirmGenerateModal .centered-modal-content button { background-color: #007aff; color: white; border: none; border-radius: 10px; padding: 10px 20px; cursor: pointer; font-size: 16px; margin: 10px; transition: all 0.3s; } #confirmGenerateModal .centered-modal-content button:hover { background-color: #005bb5; border: 1px solid #007aff; } #role-management { padding: 20px; background-color: white; border-radius: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } /* 角色项的默认样式 */ .role-item { background-color: white; /* 默认背景色 */ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */ border-radius: 10px; /* 圆角效果 */ overflow: hidden; /* 确保圆角效果生效 */ border: 2px solid transparent; /* 默认边框为透明 */ transition: all 0.3s ease; /* 过渡效果 */ margin-bottom: 20px; /* 每个角色之间的间距 */ padding: 10px; /* 内边距 */ } /* 置顶角色的样式 */ .role-item.top-role { background-color: #d3d3d3; /* 灰色背景 */ } /* 鼠标悬停时的样式 */ .role-item:hover { background-color: #e6f7ff; /* 悬停时背景色 */ border-color: #1169ff; /* 悬停时边框颜色 */ border-width: 4px; /* 悬停时边框大小 */ border-radius: 15px; /* 悬停时的圆角 */ } /* 置顶角色在悬停时的样式 */ .role-item.top-role:hover { background-color: #d3d3d3; /* 保持灰色背景不变 */ border-color: #1169ff; /* 悬停时边框颜色 */ border-width: 4px; /* 悬停时边框大小 */ border-radius: 15px; /* 悬停时的圆角 */ } .role-item h3 { margin-top: 0; } .role-item ul { padding-left: 20px; } .create-role-button { background-color: #007aff; color: white; border: none; padding: 10px 20px; border-radius: 10px; cursor: pointer; font-size: 16px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: background-color 0.3s; margin-left: 20px; /* 与标题之间的间距 */ } .create-role-button:hover { background-color: #005bb5; } </style> </head> <body> <div class="sidebar" id="sidebar"> <button onclick="showTable()">License 管理</button> <button onclick="showUserManagement()">用户管理</button> <button onclick="showRoleManagement()">角色管理</button> </div> <div class="content" id="content"> <button class="toggle-sidebar" onclick="toggleSidebar()">←</button> <header> <h1>XUGU License 管理平台</h1> <div> <!-- <button class="upload-button" onclick="window.location.href='/static/upload_xlsx/index.html'" style="display: none;">Upload File</button> --> <!-- 默认隐藏 --> <button class="user-button" onclick="toggleUserInfo()" id="username">User</button> </div> </header> <div id="table-container"> <table id="applications-table"> <thead> <tr> <th>创建人</th> <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th> <th>关联项目</th> <th>销售人员</th> <th>技服人员</th> <th>总节点数</th> <th>使用单位</th> <th>产品名称</th> <th>版本</th> <th>节点数</th> <th>License状态</th> </tr> </thead> <tbody> </tbody> </table> <div class="pagination"> <button id="prev-page">上一页</button> <button id="next-page">下一页</button> <select id="page-selector" class="flat-select"></select> <span id="pagination-info">第 1 页,共 0 页</span> <!-- 新增信息显示区域 --> <div id="capture-license-button-container"> <!-- 按钮将在这里插入 --> </div> <!-- <button class="CaptureLicenseOnce-button" onclick="CaptureLicenseOncefunc()">获取最新license</button> 动态插入按钮的容器 --> </div> </div> <!-- License 详细信息的模态框 --> <div id="detailsModal" class="modal"> <div class="modal-content"> <span class="close" onclick="closeModal('detailsModal')">×</span> <h3>License 详细信息</h3> <div id="detailsContent"></div> <button class="close-button" onclick="closeModal('detailsModal')">关闭</button> </div> </div> <!-- 用户管理的添加用户 --> <div id="user-management" style="display: none;"> <div style="display: flex; align-items: center; justify-content: space-between;"> <h2>用户管理</h2> <button id="addUserButton" class="create-role-button" style="display: none;">添加用户</button> <!-- 默认隐藏 --> </div> <table id="users-table"> <thead> <tr> <th>用户名</th> <th>电话</th> <th>邮箱</th> <th>权限</th> <th>账号</th> </tr> </thead> <tbody> </tbody> </table> </div> <!-- 新增的角色管理容器 --> <div id="role-management" style="display: none;"> <div style="display: flex; align-items: center; justify-content: space-between;"> <h2>角色管理</h2> <button id="createRoleButton" class="create-role-button">创建角色</button> </div> <div id="roles-container"></div> </div> </div> <!-- License 管理的弹出菜单 --> <div id="licenseActionModal" class="modal"> <div class="modal-content action-modal-content" id="licenseActionModalContent"> <span class="close" onclick="closeModal('licenseActionModal')">×</span> <!-- <button onclick="showExtraInfo()">查看额外信息</button> <button onclick="modifyLicenseInfo()">修改信息</button> 新增的修改信息按钮 --> <!-- <button onclick="showDistributionHistory()">分发历史</button> <button onclick="confirmDelete()">删除</button> --> </div> </div> <!-- 修改信息的表单框 --> <div id="modifyLicenseModal" class="modal"> <div class="modify-license-modal-content"> <span class="close" onclick="closeModal('modifyLicenseModal')">×</span> <h3>修改License信息</h3> <form id="modifyLicenseForm"> <label for="creator">创建人:</label> <input type="text" id="creator" name="creator" required><br><br> <label for="applicationDate">申请日期:</label> <input type="date" id="applicationDate" name="applicationDate" class="form-control" required><br><br> <label for="associatedProject">关联项目:</label> <input type="text" id="associatedProject" name="associatedProject" required><br><br> <label for="salesPerson">销售人员:</label> <input type="text" id="salesPerson" name="salesPerson" required><br><br> <label for="salesEmail">销售邮箱:</label> <input type="email" id="salesEmail" name="salesEmail" required><br><br> <label for="supportPerson">技服人员:</label> <input type="text" id="supportPerson" name="supportPerson" required><br><br> <label for="supportEmail">技服邮箱:</label> <input type="email" id="supportEmail" name="supportEmail" required><br><br> <label for="totalNodes">总节点数:</label> <input type="number" id="totalNodes" name="totalNodes" class="form-control" required><br><br> <label for="company">使用单位:</label> <input type="text" id="company" name="company" required><br><br> <label for="productName">产品名称:</label> <input type="text" id="productName" name="productName" required><br><br> <label for="version"> 数据库版本: </label> <input type="text" id="version" name="version" required><br><br> <label for="nodeCount">节点数:</label> <input type="number" id="nodeCount" name="nodeCount" class="form-control" required><br><br> <button type="button" onclick="saveLicenseChanges()">保存</button> </form> </div> </div> <!-- 用户管理的弹出菜单 --> <div id="userActionModal" class="modal"> <div class="modal-content action-modal-content" id="userActionModalContent"> <span class="close" onclick="closeModal('userActionModal')">×</span> <button onclick="showMoreUserInfo()">更多用户信息</button> <button onclick="showUserLicenseHistory()">查看license分发记录</button> <button onclick="modifyUser()">修改用户</button> </div> </div> <!-- 用户管理的添加用户 --> <div id="addUserModal" class="modal"> <div class="centered-modal-content" style="height: 50vh; overflow-y: auto;"> <span class="close" onclick="closeModal('addUserModal')">×</span> <h3>添加用户</h3> <form id="addUserForm"> <div class="form-group"> <label for="addUsername">用户名:</label> <input type="text" id="addUsername" name="username" class="flat-rounded-input" required> </div> <div class="form-group"> <label for="addPassword">密码:</label> <input type="password" id="addPassword" name="password" class="flat-rounded-input" required> </div> <div class="form-group"> <label for="addAccount">账号:</label> <input type="text" id="addAccount" name="account" class="flat-rounded-input" required> </div> <div class="form-group"> <label for="addTelephone">电话:</label> <input type="text" id="addTelephone" name="telephone" class="flat-rounded-input" required> </div> <div class="form-group"> <label for="addEmail">邮箱:</label> <input type="email" id="addEmail" name="email" class="flat-rounded-input" required> </div> <button type="button" onclick="saveNewUser()" class="flat-rounded-button">保存</button> </form> </div> </div> <!-- 邮箱和用户选择弹出框 --> <div id="emailModal" class="modal"> <div class="modal-content centered-modal-content" style="height: 45vh; overflow-y: auto;"> <span class="close" onclick="closeModal('emailModal')">×</span> <!-- 邮箱输入部分 --> <label for="emailInput1" class="email-modal-label">选中要发送的邮箱:</label> <div id="emailInputs"> <input type="text" id="emailInput1" class="email-modal-input"> </div> <br> <button onclick="addEmailInput()" class="add-email-button">添加邮箱</button> <!-- 用户选择部分 --> <label for="userSelect1" class="email-modal-label">选择要分发的用户:</label> <div id="userInputs"></div> <button onclick="addUserInput()" class="add-email-button">添加用户</button> <!-- 发送按钮 --> <button onclick="sendEmail()" class="ios-button">发送</button> </div> </div> <!-- 其他模态框不变 --> <div id="extraInfoModal" class="modal"> <div class="modal-content"> <span class="close" onclick="closeModal('extraInfoModal')">×</span> <div id="extraInfoContent" class="extra-info"></div> </div> </div> <div id="userModal" class="user-info"> <span class="close apple-close" onclick="closeUserInfo()">×</span> <!-- 关闭按钮 --> <div id="userInfoContent"></div> <br> <button class="apple-logout-button" onclick="logout()">退出</button> </div> <!-- license删除模态框--> <div id="confirmDeleteModal" class="modal"> <div class="centered-modal-content"> <span class="close" onclick="closeModal('confirmDeleteModal')">×</span> </div> </div> <div id="confirmGenerateModal" class="modal"> <div class="centered-modal-content" style="height: 15vh; overflow-y: auto;"> <span class="close" onclick="closeModal('confirmGenerateModal')">×</span> <p>确认生成License吗?</p> <button id="confirm-generate-button">确认</button> <button onclick="closeModal('confirmGenerateModal')">取消</button> </div> </div> <div id="distributionHistoryModal" class="modal"> <div class="centered-modal-content"> <span class="close" onclick="closeModal('distributionHistoryModal')">×</span> <h3>分发历史</h3> <div id="distributionHistoryContent" class="extra-info"></div> </div> </div> <script> //翻页有关,还需优化 let currentPage = 1; let pageSize = 10; let LisOffset = 1; let totalPages = 0; // 存储总页数 let selectedPage =1; let nextPage =1; let prevPage = 10; //用户token const token = localStorage.getItem('Authorization'); //选中行的数据 let selectedRowData = null;//选中行的数据 let isAscending = true; let userMap = {}; // 用于存储用户名和用户ID的映射 let currentUserRole = ''; // 新增变量存储当前用户的权限 let currentUserName = ''; // 新增变量存储当前用户的名字 let userPermissions = [];// 全局变量,用于存储用户权限 let LicApplicationData = []; // 全局变量存储数据 let currentRolePermissions = []; // 这是您获取的当前角色的权限列表 function checkPermission(permission) { console.log(`检查权限: ${permission} - ${hasPermission ? '有权限' : '无权限'}`); return userPermissions.includes(permission); } async function initialize() { await fetchUsername(); // 确保 fetchUsername 完成 fetchApplications(1, 10); // 然后再调用 fetchApplications } //获取license展示信息 function fetchApplications(page, size) { fetch(`http://${serverIP}:${serverPort}/api/admin/GetAllLicenseInfo?page=${page}&pageSize=${size}`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { //selectedRowData = data.data; LicApplicationData = data.data; // 将接收到的数据存储到全局变量 console.log("lic数据",data); // 输出获取的数据结构 console.log("z该死的权限数组",userPermissions); const hasGeneratePermission = userPermissions.includes("generate_license"); const hasDistributePermission = userPermissions.includes("dispat_license"); // 更新总页数 //totalPages = Math.ceil(data.total / 10); // 在控制台打印权限结果 console.log(`hasGeneratePermission: ${hasGeneratePermission}, hasDistributePermission: ${hasDistributePermission}`); totalPages = Math.ceil(data.total / 10); const tableBody = document.querySelector('#applications-table tbody'); const tableHead = document.querySelector('#applications-table thead tr'); tableBody.innerHTML = ''; tableHead.innerHTML = ` <th></th> <!-- 添加一个空的表头用于放置下拉按钮 --> <th>创建人</th> <th>申请日期 </th> <!-- <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>--> <th>关联项目</th> <th>销售人员</th> <th>技服人员</th> <th>总节点数</th> <th>使用单位</th> <th>操作</th> <!-- 新增的表头用于显示操作按钮 --> `; data.data.forEach(applicationArray => { const firstApplication = applicationArray[0]; let showGenerateButton = false; // Check if any child row has LicenseFlage as "未生成" applicationArray.forEach(detail => { if (detail.LicenseFlage === "未生成") { showGenerateButton = true; } }); // 创建主行 const row = document.createElement('tr'); const dropdownButton = document.createElement('button'); // 使用CSS创建一个箭头图标 dropdownButton.innerHTML = ''; dropdownButton.classList.add('arrow-icon'); dropdownButton.style.cursor = 'pointer'; row.innerHTML = ` <td></td> <!-- 空的单元格用于放置下拉按钮 --> <td>${createEllipsisText(firstApplication.Creator)}</td> <td>${createEllipsisText(firstApplication.ApplicationDate)} ${firstApplication.ApplicationTime}</td> <td>${createEllipsisText(firstApplication.GlxmName)}</td> <td>${createEllipsisText(firstApplication.SalesPerson)}</td> <td>${createEllipsisText(firstApplication.SupportPerson)}</td> <td>${firstApplication.TotalNodes}</td> <td>${createEllipsisText(firstApplication.Company)}</td> `; row.querySelector('td').appendChild(dropdownButton); // 添加 License 状态按钮 (父级行) if (hasGeneratePermission || hasDistributePermission) { const licenseStatusCell = document.createElement('td'); if (hasGeneratePermission && showGenerateButton) { licenseStatusCell.innerHTML += `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${firstApplication.oa_request_id}', true)">生成</button>`; } else if (hasDistributePermission && firstApplication.LicenseFlage === "已生成") { licenseStatusCell.innerHTML += `<button class="license-status-btn distribute" onclick="showEmailModal('${firstApplication.SupportEmail}', '${firstApplication.SalesEmail}','','${firstApplication.oa_request_id}')">分发</button>`; } // 添加一个分隔符 licenseStatusCell.innerHTML += `<span style="margin: 0 10px; display: inline-block; width: 1px; height: 20px; background-color: #ccc;"></span>`; // 在这里添加“查看详情”按钮 licenseStatusCell.innerHTML += `<button class="license-status-btn view-details" onclick="showDetailsModal('${firstApplication.UniqueID}', false)">查看详情</button>`; row.appendChild(licenseStatusCell); } tableBody.appendChild(row); // 多行内容及表头 (子行) const detailRow = document.createElement('tr'); const detailCell = document.createElement('td'); detailCell.colSpan = 11; // 占满所有列 detailCell.style.display = 'none'; const detailTable = document.createElement('table'); // 添加表头 const detailTableHeader = document.createElement('tr'); detailTableHeader.innerHTML = ` <th>产品名称</th> <th>版本</th> <th>节点数</th> <th>处理器</th> <th>操作系统</th> <th>主MAC地址</th> <th>副MAC地址</th> <th> 查看</th> `; detailTable.appendChild(detailTableHeader); // 添加详细信息行 (子行) applicationArray.forEach(detail => { const detailInnerRow = document.createElement('tr'); detailInnerRow.innerHTML = ` <td>${createEllipsisText(detail.ProductName)}</td> <td>${createEllipsisText(detail.ProductVersion)}</td> <td>${detail.NodeCount}</td> <td>${createEllipsisText(detail.oa_cpu)}</td> <td>${createEllipsisText(detail.oa_operating_system)}</td> <td>${createEllipsisText(detail.oa_main_mac)}</td> <td>${createEllipsisText(detail.oa_second_mac)}</td> `; //保留这里的代码,涉及到子行的单独申请 // 添加 License 状态按钮 (子行) // if (hasGeneratePermission || hasDistributePermission) { // const licenseStatusDetailCell = document.createElement('td'); // if (hasGeneratePermission && detail.LicenseFlage === "未生成") { // // 子行点击生成按钮时,传递 UniqueID 和 false 表示这是子行 // licenseStatusDetailCell.innerHTML = `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${detail.UniqueID}', false)">生成</button>`; // } else if (hasDistributePermission && detail.LicenseFlage === "已生成") { // // 子行点击分发按钮时,传递 UniqueID 用于分发操作 // licenseStatusDetailCell.innerHTML = `<button class="license-status-btn distribute" onclick="showEmailModal('${detail.SupportEmail}', '${detail.SalesEmail}', '${detail.UniqueID}','')">分发</button>`; // } // detailInnerRow.appendChild(licenseStatusDetailCell); // } detailTable.appendChild(detailInnerRow); // 添加“查看详情”按钮 (子行) // const viewDetailsCell = document.createElement('td'); // viewDetailsCell.innerHTML = `<button class="license-status-btn view-details" onclick="showDetailsModal('${detail.UniqueID}', true)">查看详情</button>`; // detailInnerRow.appendChild(viewDetailsCell); // detailTable.appendChild(detailInnerRow); // 仅当主行状态为“分发”时添加“下载lic”按钮 // 创建一个新的单元格用于放置按钮 const actionCell = document.createElement('td'); // 创建按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.classList.add('button-container'); // 创建“查看详情”按钮 (子行) const viewDetailsButton = document.createElement('button'); viewDetailsButton.classList.add('license-status-btn', 'view-details'); viewDetailsButton.textContent = '查看详情'; viewDetailsButton.onclick = () => showDetailsModal(detail.UniqueID, true); // 将“查看详情”按钮添加到按钮容器 buttonContainer.appendChild(viewDetailsButton); // 仅当主行状态为“已生成”时添加“下载lic”按钮 if (firstApplication.LicenseFlage === "已生成") { const downloadLicButton = document.createElement('button'); downloadLicButton.classList.add('license-status-btn', 'download-lic'); downloadLicButton.textContent = '下载lic'; // 绑定当前行的 lic1 和 lic2 数据 downloadLicButton.onclick = () => downloadLicenseFiles(detail.lic1, detail.lic2); // 将“下载lic”按钮添加到按钮容器 buttonContainer.appendChild(downloadLicButton); } // 将按钮容器添加到actionCell actionCell.appendChild(buttonContainer); // 将actionCell添加到当前子行 detailInnerRow.appendChild(actionCell); // 将子行添加到详细信息表格 detailTable.appendChild(detailInnerRow); // 为每个详细信息行添加点击事件 (子行) detailInnerRow.addEventListener('click', (event) => { if (!event.target.closest('button')) { openActionModal(event, detail, 'licenseActionModal'); } }); detailInnerRow.addEventListener('contextmenu', (event) => { event.preventDefault(); if (!event.target.closest('button')) { openActionModal(event, detail, 'licenseActionModal'); } }); }); detailCell.appendChild(detailTable); detailRow.appendChild(detailCell); tableBody.appendChild(detailRow); // 主行的点击事件,用于切换下拉菜单的显示隐藏 // row.addEventListener('click', (event) => { // if (!event.target.closest('button')) { // 如果点击的不是按钮 // detailCell.style.display = detailCell.style.display === 'none' ? 'table-cell' : 'none'; // } // }); // // 点击下拉按钮切换显示隐藏 // dropdownButton.addEventListener('click', (event) => { // event.stopPropagation(); // 阻止事件冒泡到行点击事件 // detailCell.style.display = detailCell.style.display === 'none' ? 'table-cell' : 'none'; // }); row.addEventListener('click', (event) => { if (!event.target.closest('button')) { // 如果点击的不是按钮 // const isExpanded = detailCell.style.display === 'table-cell'; // detailCell.style.display = isExpanded ? 'none' : 'table-cell'; // row.classList.toggle('expanded-row', !isExpanded); // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标 if (!event.target.closest('button')) { const isExpanded = detailCell.style.display === 'table-cell'; // 收回其他行 closeAllExpandedRows(); // 展开/收起当前行 detailCell.style.display = isExpanded ? 'none' : 'table-cell'; row.classList.toggle('expanded-row', !isExpanded); dropdownButton.classList.toggle('rotate-arrow', !isExpanded); } } }); dropdownButton.addEventListener('click', (event) => { // event.stopPropagation(); // 阻止事件冒泡到行点击事件 // const isExpanded = detailCell.style.display === 'table-cell'; // detailCell.style.display = isExpanded ? 'none' : 'table-cell'; // row.classList.toggle('expanded-row', !isExpanded); // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标 event.stopPropagation(); // 阻止事件冒泡到行点击事件 const isExpanded = detailCell.style.display === 'table-cell'; // 收回其他行 closeAllExpandedRows(); // 展开/收起当前行 detailCell.style.display = isExpanded ? 'none' : 'table-cell'; row.classList.toggle('expanded-row', !isExpanded); dropdownButton.classList.toggle('rotate-arrow', !isExpanded); }); }); // 分页和其他控制逻辑 // 更新分页信息 // totalPages = Math.ceil(data.total / pageSize); document.getElementById('pagination-info').textContent = `第 ${currentPage} 页,共 ${totalPages} 页`; document.getElementById('prev-page').disabled = currentPage <= 1; document.getElementById('next-page').disabled = currentPage >= totalPages; const pageSelector = document.getElementById('page-selector'); pageSelector.innerHTML = ''; for (let i = 1; i <= totalPages; i++) { const option = document.createElement('option'); option.value = i; option.text = i; if (i === selectedPage) { option.selected = true; document.getElementById('pagination-info').textContent = `第 ${selectedPage} 页,共 ${totalPages} 页`; // LisOffset = selectedPage // pageSize = LisOffset + 10; // document.getElementById('prev-page').disabled = currentPage <= 1; // document.getElementById('next-page').disabled = currentPage >= totalPages; } pageSelector.appendChild(option); } }); } function checkCaptureLicensePermission() { // 获取插入按钮的容器元素 const container = document.getElementById('capture-license-button-container'); if (container) { // 确保容器元素存在 if (userPermissions.includes('capture_license_once_to_db')) { // 如果有权限,插入按钮 const CaptureLicensebuttonHtml = `<button class="CaptureLicenseOnce-button" onclick="CaptureLicenseOncefunc()">获取最新license</button>`; container.innerHTML = CaptureLicensebuttonHtml; } else { // 如果没有权限,确保不显示按钮 container.innerHTML = ''; // 清空容器 } } else { console.error('找不到 capture-license-button-container 元素'); } } let currentOffset = 1; const itemsPerPage = 10; // 添加页数选择框的事件监听器 document.getElementById('page-selector').addEventListener('change', (event) => { selectedPage = parseInt(event.target.value, 10); const startRecord = (selectedPage - 1) * 10 + 1; const endRecord = startRecord + 10; LisOffset = selectedPage pageSize = LisOffset* 10; currentPage = selectedPage currentOffset = startRecord endOffset = endRecord fetchApplications(startRecord, endRecord); }); // 分页按钮事件监听器 document.getElementById('prev-page').addEventListener('click', () => { if (currentPage > 1) { currentPage--; selectedPage-- currentOffset -= itemsPerPage; const startOffset = currentOffset; const endOffset = currentOffset + itemsPerPage - 1; fetchApplications(startOffset, endOffset); } }); document.getElementById('next-page').addEventListener('click', () => { if (currentPage < totalPages) { currentPage++ selectedPage++ LisOffset += pageSize-LisOffset; pageSize += 10; // 增加页数时,增加 pageSize,规则可自定义 currentOffset += itemsPerPage; const startOffset = currentOffset; const endOffset = currentOffset + itemsPerPage - 1; fetchApplications(startOffset, endOffset); } }); // 页面加载时默认调用第一页的数据 //fetchApplications(1); // 页面初始化时调用 fetchUsername 函数 //fetchApplications(LisOffset,pageSize); //排序 // function sortTableByDate() { // applicationData.sort((a, b) => { // const dateTimeA = `${a[0].ApplicationDate} ${a[0].ApplicationTime}`; // const dateTimeB = `${b[0].ApplicationDate} ${b[0].ApplicationTime}`; // return isAscending ? dateTimeA.localeCompare(dateTimeB) : dateTimeB.localeCompare(dateTimeA); // }); // renderTable(applicationData); // 排序后重新渲染表格 // isAscending = !isAscending; // 切换排序顺序 // } // 关闭所有已经展开的行 function closeAllExpandedRows() { const allExpandedRows = document.querySelectorAll('.expanded-row'); allExpandedRows.forEach(expandedRow => { const detailCell = expandedRow.nextElementSibling.querySelector('td'); if (detailCell && detailCell.style.display === 'table-cell') { detailCell.style.display = 'none'; expandedRow.classList.remove('expanded-row'); const dropdownButton = expandedRow.querySelector('.arrow-icon'); if (dropdownButton) { dropdownButton.classList.remove('rotate-arrow'); } } }); } // 创建带省略号的文本,并在鼠标悬停时显示完整内容 function createEllipsisText(text) { const maxLength = 20; // 最大显示字符数 if (text == null || typeof text !== 'string') { return ''; // 如果 text 是 null、undefined 或不是字符串,返回空字符串 } if (text.length > maxLength) { const span = document.createElement('span'); span.textContent = text.substring(0, maxLength) + '...'; span.title = text; // 鼠标悬停时显示完整内容 return span.outerHTML; } return text; } //生成licensestr function confirmGenerateLicense(id, isParentRow) { const confirmGenerateModal = document.getElementById('confirmGenerateModal'); confirmGenerateModal.style.display = 'block'; document.getElementById('confirm-generate-button').onclick = function() { generateLicense(id, isParentRow); }; } function generateLicense(id, isParentRow) { const payload = isParentRow ? { oa_request_id: id } : { uniqueID: id }; fetch('http://${serverIP}:${serverPort}/api/admin/GenerateLicense', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }) .then(response => response.json()) .then(data => { if (data.success) { alert('License生成成功!'); const startOffset = currentOffset; // 当前的起始位置 const endOffset = startOffset + itemsPerPage - 1; // 计算结束位置 fetchApplications(startOffset, endOffset); // 传入计算好的起始和结束位置 // fetchApplications(LisOffset, pageSize); } else { alert('License生成失败:' + data.error); } closeModal('confirmGenerateModal'); }); } //主动抓取一次Licen数据 function CaptureLicenseOncefunc() { // 显示加载模态框 const loadingModal = document.createElement('div'); loadingModal.classList.add('modal-content', 'apple-modal-content'); loadingModal.innerHTML = ` <h3>正在获取 License 信息...</h3> <div class="progress-bar" style="width: 100%; height: 20px; background-color: #e0e0e0;"> <div class="progress" style="width: 50%; height: 100%; background-color: #007aff;"></div> </div> `; document.body.appendChild(loadingModal); // 定义超时函数 const timeoutPromise = new Promise((_, reject) => { setTimeout(() => { reject(new Error('获取超时')); }, 10000); // 10秒超时 }); // 发起 GET 请求的 Promise const fetchPromise = fetch('http://${serverIP}:${serverPort}/api/admin/GetCaptureLicenseOnce', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }).then(response => response.json()); // 使用 Promise.race 来竞争两个 Promise,哪个先返回就使用哪个 Promise.race([fetchPromise, timeoutPromise]) .then(data => { // 先关闭进度条 document.body.removeChild(loadingModal); // 显示成功或失败提示 if (data.success) { alert('License 获取成功!'); } else { alert('获取失败:' + data.error); } }) .catch(error => { // 先关闭进度条 document.body.removeChild(loadingModal); // 显示错误提示 alert(error.message); // 如果超时或请求失败 }); } function downloadLicenseFiles(lic1, lic2) { // 下载license.dat文件 if (lic1) { const blob1 = new Blob([lic1], { type: 'text/plain' }); const link1 = document.createElement('a'); link1.href = URL.createObjectURL(blob1); link1.download = 'license.dat'; link1.click(); } // 如果lic2不为空,下载license2.dat文件 if (lic2) { const blob2 = new Blob([lic2], { type: 'text/plain' }); const link2 = document.createElement('a'); link2.href = URL.createObjectURL(blob2); link2.download = 'license2.dat'; link2.click(); } } //查看lic所有信息 // 查看lic所有信息 function showDetailsModal(uniqueID, isChildRow = false, page = 1) { console.log("当前 uniqueID:", uniqueID); console.log("当前 isChildRow:", isChildRow); console.log("当前页码:", page); let selectedData = null; const itemsPerPage = 1; // 每页只显示一个子行数据 let currentPage = page; // 当前页码 // 查找主行和子行数据 console.log("查找主行和子行数据"); let selectedApplicationArray = null; for (let applicationArray of LicApplicationData) { if (applicationArray.some(data => data.UniqueID === uniqueID)) { selectedApplicationArray = applicationArray; break; } } if (!selectedApplicationArray) { console.error('未找到对应的记录,UniqueID:', uniqueID); alert('未找到对应的记录,请检查数据'); return; } let detailsHtml = `<div class="apple-modal-content">`; // 如果是子行,直接显示该子行的信息,不进行分页 if (isChildRow) { // 查找唯一的子行数据 const childData = selectedApplicationArray.find(data => data.UniqueID === uniqueID); if (childData) { detailsHtml += ` <p class="apple-modal-text"><strong>产品名称:</strong> ${childData.ProductName}</p> <p class="apple-modal-text"><strong>版本:</strong> ${childData.ProductVersion}</p> <p class="apple-modal-text"><strong>节点数:</strong> ${childData.NodeCount}</p> <p class="apple-modal-text"><strong>处理器:</strong> ${childData.oa_cpu}</p> <p class="apple-modal-text"><strong>操作系统:</strong> ${childData.oa_operating_system}</p> <p class="apple-modal-text"><strong>主MAC地址:</strong> ${childData.oa_main_mac}</p> <p class="apple-modal-text"><strong>副MAC地址:</strong> ${childData.oa_second_mac}</p> `; } else { detailsHtml += `<p>未找到对应的子行记录。</p>`; } } else { // 如果是主行,使用分页显示主行和子行信息 // 计算总页数 const totalItems = selectedApplicationArray.length; const totalPages = totalItems + 1; // 主行为第一页,后续为子行 console.log("totalItems: ", totalItems); console.log("totalPages: ", totalPages); if (currentPage === 1) { // 显示主行内容(第一页) detailsHtml += `<h3 class="apple-modal-title">项目信息</h3>`; const firstData = selectedApplicationArray[0]; detailsHtml += ` <p class="apple-modal-text"><strong>创建人:</strong> ${firstData.Creator}</p> <p class="apple-modal-text"><strong>申请日期:</strong> ${firstData.ApplicationDate}</p> <p class="apple-modal-text"><strong>关联项目:</strong> ${firstData.GlxmName}</p> <p class="apple-modal-text"><strong>销售人员:</strong> ${firstData.SalesPerson}</p> <p class="apple-modal-text"><strong>技服人员:</strong> ${firstData.SupportPerson}</p> <p class="apple-modal-text"><strong>总节点数:</strong> ${firstData.TotalNodes}</p> <p class="apple-modal-text"><strong>使用单位:</strong> ${firstData.Company}</p> `; } else { // 显示子行内容(从第二页开始) const dataIndex = currentPage - 2; // 当前页对应的子行数据索引,主行占用第一页 const data = selectedApplicationArray[dataIndex]; detailsHtml += ` <h4 class="apple-modal-subtitle">集群 ${currentPage - 1}</h4> <p class="apple-modal-text"><strong>产品名称:</strong> ${data.ProductName}</p> <p class="apple-modal-text"><strong>版本:</strong> ${data.ProductVersion}</p> <p class="apple-modal-text"><strong>节点数:</strong> ${data.NodeCount}</p> <p class="apple-modal-text"><strong>处理器:</strong> ${data.oa_cpu}</p> <p class="apple-modal-text"><strong>操作系统:</strong> ${data.oa_operating_system}</p> <p class="apple-modal-text"><strong>主MAC地址:</strong> ${data.oa_main_mac}</p> <p class="apple-modal-text"><strong>副MAC地址:</strong> ${data.oa_second_mac}</p> `; } // 添加分页按钮 detailsHtml += `<div class="pagination-controls" style="text-align: center;">`; if (currentPage > 1) { detailsHtml += `<button style="font-size: 12px; padding: 5px 10px; width: 80px;" onclick="showDetailsModal('${uniqueID}', ${isChildRow}, ${currentPage - 1})">上一页</button>`; } detailsHtml += `<hr style="margin: 10px 0; border-top: 1px solid #ccc;">`; // 分隔符 if (currentPage < totalPages) { detailsHtml += `<button style="font-size: 12px; padding: 5px 10px; width: 80px;" onclick="showDetailsModal('${uniqueID}', ${isChildRow}, ${currentPage + 1})">下一页</button>`; } detailsHtml += `</div>`; } detailsHtml += `</div>`; console.log("detailsHtml: ", detailsHtml); document.getElementById('detailsContent').innerHTML = detailsHtml; document.getElementById('detailsModal').style.display = 'block'; } // 用户管理菜单栏 function openUserActionModal(event, data, modalId) { selectedRowData = data; let modal = document.getElementById(modalId); const modalContent = modal.querySelector('.modal-content'); // 清空之前的内容 modalContent.innerHTML = ` <span class="close" onclick="closeModal('${modalId}')">×</span> `; // 动态生成更多用户信息按钮 if (userPermissions.includes('read_user')) { modalContent.innerHTML += `<button onclick="showMoreUserInfo(); closeModal('${modalId}');">更多用户信息</button>`; } // 检查是否有 `update_user` 权限,决定是否显示修改用户按钮 if (userPermissions.includes('update_user')) { modalContent.innerHTML += `<button onclick="modifyUser(); closeModal('${modalId}');">修改用户</button>`; } // 检查是否有 `delete_user` 权限,决定是否显示删除按钮 if (userPermissions.includes('delete_user')) { modalContent.innerHTML += `<button onclick="confirmDeleteUser('${data.UniqueID}'); closeModal('${modalId}');">删除用户</button>`; } // 显示菜单位置 modalContent.style.top = `${event.clientY}px`; modalContent.style.left = `${event.clientX}px`; modal.style.display = 'block'; } // 为用户管理界面的每一行添加点击和右键事件监听器 function fetchUsers() { fetch('http://${serverIP}:${serverPort}/api/admin/userInfoAll', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { const tableBody = document.querySelector('#users-table tbody'); tableBody.innerHTML = ''; data.data.forEach(user => { // 如果 ACCOUNT 字段为 'admin',则跳过这一行 if (user.Account === 'admin') { return; } const row = document.createElement('tr'); row.innerHTML = ` <td>${user.Username}</td> <td>${user.Telephone}</td> <td>${user.Email}</td> <td>${user.Role}</td> <td>${user.Account}</td> `; row.addEventListener('click', (event) => { if (!event.target.classList.contains('ios-button')) { openUserActionModal(event, user, 'userActionModal'); } }); row.addEventListener('contextmenu', (event) => { event.preventDefault(); if (!event.target.classList.contains('ios-button')) { openUserActionModal(event, user, 'userActionModal'); } }); tableBody.appendChild(row); }); }); } //查看用户lic历史 function showUserLicenseHistory() { fetch(`http://${serverIP}:${serverPort}/api/admin/GetlicenseRecordInfoByUser`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ Id: selectedRowData.Id, UserName: selectedRowData.Username, Page: 1, PageSize: 10 }) }) .then(response => response.json()) .then(data => { const extraInfoContent = document.getElementById('extraInfoContent'); extraInfoContent.innerHTML = `<h3>License 分发记录</h3>`; if (data.data && data.data.length > 0) { const table = document.createElement('table'); table.style.width = '100%'; table.style.borderCollapse = 'collapse'; table.style.marginTop = '10px'; const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); const headers = ['分发日期', '关联项目', '产品名称', '版本', '节点数', 'Company']; headers.forEach(headerText => { const th = document.createElement('th'); th.textContent = headerText; th.style.border = '1px solid #ddd'; th.style.padding = '8px'; th.style.backgroundColor = '#f1f1f1'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); const tbody = document.createElement('tbody'); data.data.forEach(record => { const row = document.createElement('tr'); const cells = [ record.up_time.Time, record.AssociatedProject, record.ProductName, record.Version, record.NodeCount, record.Company ]; cells.forEach(cellText => { const td = document.createElement('td'); td.textContent = cellText; td.style.border = '1px solid #ddd'; td.style.padding = '8px'; row.appendChild(td); }); tbody.appendChild(row); }); table.appendChild(tbody); extraInfoContent.appendChild(table); } else { extraInfoContent.innerHTML += `<p>没有找到分发记录。</p>`; } document.getElementById('extraInfoModal').style.display = 'block'; }); } //用户菜单栏 function openActionModal(event, data, modalId) { selectedRowData = data; let modal = document.getElementById(modalId); const modalContent = modal.querySelector('.modal-content'); // 清空之前的内容 modalContent.innerHTML = ` <span class="close" onclick="closeModal('${modalId}')">×</span> `; // 动态生成查看分发记录 if (userPermissions.includes('read_license_record')) { modalContent.innerHTML += ` <button onclick="showDistributionHistory(); closeModal('${modalId}');">查看分发记录</button> `; } // 动态生成查看额外信息 if (userPermissions.includes('read_license')) { modalContent.innerHTML += ` <button onclick="showExtraInfo(); closeModal('${modalId}');">查看额外信息</button> `; } // 检查是否有 `update_license` 权限,决定是否显示修改信息按钮 if (userPermissions.includes('update_license')) { modalContent.innerHTML += `<button onclick="modifyLicenseInfo(); closeModal('${modalId}');">修改信息</button>`; } // 检查是否有 `delete_license` 权限,决定是否显示删除按钮 if (userPermissions.includes('delete_license')) { modalContent.innerHTML += `<button onclick="confirmDelete(); closeModal('${modalId}');">删除</button>`; } // 显示菜单位置 modalContent.style.top = `${event.clientY}px`; modalContent.style.left = `${event.clientX}px`; modal.style.display = 'block'; } function closeModal(modalId) { document.getElementById(modalId).style.display = 'none'; } // function closeUserInfo() { // document.getElementById('userModal').style.display = 'none'; // } //删除一行lic信息 function confirmDelete() { const confirmDeleteModal = document.getElementById('confirmDeleteModal'); confirmDeleteModal.innerHTML = ` <div class="centered-modal-content"> <span class="close" onclick="closeModal('confirmDeleteModal')" style="font-size: 24px; font-weight: bold; color: #555; cursor: pointer;">×</span> <div style="margin-bottom: 15px; border: 1px solid #ddd; padding: 10px; border-radius: 10px;"> <p><strong>申请日期:</strong> ${selectedRowData.ApplicationDate}</p> <p><strong>关联项目:</strong> ${selectedRowData.AssociatedProject}</p> <p><strong>使用单位:</strong> ${selectedRowData.Company}</p> </div> <p>确认删除此行数据吗?</p> <button class="flat-rounded-button" onclick="deleteRow()">确认</button> <button class="flat-rounded-button" onclick="closeModal('confirmDeleteModal')">取消</button> </div> `; confirmDeleteModal.style.display = 'block'; } function deleteRow() { fetch(`http://${serverIP}:${serverPort}/api/admin/deleteLicRow`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ uniqueID: selectedRowData.UniqueID }) }).then(response => { if (response.ok) { alert('删除成功'); closeModal('confirmDeleteModal'); // fetchApplications(LisOffset, pageSize); const startOffset = currentOffset; // 当前的起始位置 const endOffset = startOffset + itemsPerPage - 1; // 计算结束位置 fetchApplications(startOffset, endOffset); // 传入计算好的起始和结束位置 } else { alert('删除失败'); } }); } //添加用户 document.getElementById('addUserButton').addEventListener('click', function() { document.getElementById('addUserModal').style.display = 'block'; }); //添加用户 function saveNewUser() { const username = document.getElementById('addUsername').value.trim(); const password = document.getElementById('addPassword').value.trim(); const account = document.getElementById('addAccount').value.trim(); const telephone = document.getElementById('addTelephone').value.trim(); const email = document.getElementById('addEmail').value.trim(); // 验证每个字段都不能为空 if (!username || !password || !account || !telephone || !email) { alert('有空选项未填写'); return; } // 验证电话是否为11位数字 const phonePattern = /^\d{11}$/; if (!phonePattern.test(telephone)) { alert('电话必须是11位数字'); return; } // 验证密码长度是否至少为6位 if (password.length < 6) { alert('密码长度必须至少为6位'); return; } // 验证邮箱是否包含@符号 if (!email.includes('@')) { alert('邮箱必须包含@符号'); return; } // 验证账号长度是否至少为3位 if (account.length < 3) { alert('账号长度必须至少为3位'); return; } const newUser = { Username: username, Password: password, Account: account, Telephone: telephone, Email: email }; fetch('http://${serverIP}:${serverPort}/api/register', { // 修改为实际的API路径 method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(newUser) }) .then(response => response.json()) .then(data => { if (data.success) { alert('用户创建成功!'); fetchUsers(); // 重新加载用户列表 closeModal('addUserModal'); // 关闭模态框 } else { alert('用户创建失败:' + data.error); } }); } function deleteUser(uniqueID) { fetch('http://${serverIP}:${serverPort}/api/admin/deleteUser', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ UniqueID: uniqueID }) }) .then(response => response.json()) .then(data => { if (data.success) { alert('用户删除成功!'); fetchUsers(); // 重新加载用户列表 } else { alert('用户删除失败:' + data.error); } }) .catch(error => { console.error('Error deleting user:', error); alert('删除用户时发生错误,请稍后再试。'); }); } function confirmDeleteUser(uniqueID) { const confirmed = confirm("确认删除此用户吗?"); if (confirmed) { deleteUser(uniqueID); } } // 分发模态框 function showEmailModal(supportEmail, salesEmail, uniqueID,oa_request_id) { // 清空并设置默认值 document.getElementById('emailInputs').innerHTML = ` <div> <input type="checkbox" id="supportEmailCheckbox" value="${supportEmail}" checked> <label for="supportEmailCheckbox"> 运维邮箱: ${supportEmail}</label> </div> <div> <input type="checkbox" id="salesEmailCheckbox" value="${salesEmail}" checked> <label for="salesEmailCheckbox"> 销售邮箱: ${salesEmail}</label> </div> `; document.getElementById('userInputs').innerHTML = ''; // 清空用户输入 // 获取用户信息并填充第一个用户输入框 fetch('http://${serverIP}:${serverPort}/api/admin/distributeLicenseByUserInfo', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { const userSelect = document.createElement('select'); userSelect.id = 'userSelect1'; userSelect.className = 'email-modal-input'; data.data.forEach(user => { userMap[user.Username] = {// 存储用户名和用户ID的映射 Account: user.Account, UniqueID: user.UniqueID, Username: user.Username, Email: user.Email, Role: user.Role, Telephone:user.Telephone }; const option = document.createElement('option'); option.value = user.Username; option.textContent = user.Username; userSelect.appendChild(option); }); //document.getElementById('userInputs').appendChild(userSelect); }); document.getElementById('emailModal').style.display = 'block'; selectedRowData = { ...selectedRowData, UniqueID: uniqueID ,Oa_request_id: oa_request_id}; } function addEmailInput() { const emailInputs = document.getElementById('emailInputs'); const newInputDiv = document.createElement('div'); newInputDiv.style.display = 'flex'; newInputDiv.style.alignItems = 'center'; newInputDiv.style.marginBottom = '10px'; const newInput = document.createElement('input'); newInput.type = 'text'; newInput.className = 'email-modal-input'; newInput.style.flexGrow = '1'; newInputDiv.appendChild(newInput); const deleteButton = document.createElement('button'); deleteButton.textContent = '✕'; deleteButton.style.background = 'none'; deleteButton.style.border = 'none'; deleteButton.style.color = '#007aff'; deleteButton.style.cursor = 'pointer'; deleteButton.style.fontSize = '12px'; /* 再次缩小字体大小 */ deleteButton.style.padding = '0'; /* 移除内边距 */ deleteButton.style.marginLeft = '3px'; /* 减少与输入框的间距 */ deleteButton.style.width = '20px'; /* 限制按钮宽度 */ deleteButton.style.height = '20px'; /* 限制按钮高度 */ deleteButton.onclick = () => { newInputDiv.remove(); }; newInputDiv.appendChild(deleteButton); emailInputs.appendChild(newInputDiv); } function addUserInput() { const userInputs = document.getElementById('userInputs'); const newUserDiv = document.createElement('div'); newUserDiv.className = 'user-select-container'; newUserDiv.style.display = 'flex'; newUserDiv.style.alignItems = 'center'; newUserDiv.style.marginBottom = '10px'; const newUserSelect = document.createElement('select'); newUserSelect.className = 'email-modal-input'; newUserSelect.style.flexGrow = '1'; newUserSelect.style.marginRight = '5px'; // 添加一个默认的空白选项 const defaultOption = document.createElement('option'); defaultOption.value = ''; defaultOption.textContent = '请选择用户'; newUserSelect.appendChild(defaultOption); // 获取当前已选择的用户 const selectedValues = Array.from(document.querySelectorAll('.user-select-container select')) .map(select => select.value); // 获取用户列表并填充到选择框中 fetch('http://${serverIP}:${serverPort}/api/admin/distributeLicenseByUserInfo', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { data.data.forEach(user => { // 仅显示未被选中的用户,并且过滤掉admin用户 if (!selectedValues.includes(user.Username) && user.Username !== 'admin') { const option = document.createElement('option'); option.value = user.Username; option.textContent = user.Username; newUserSelect.appendChild(option); } }); }); const deleteButton = document.createElement('button'); deleteButton.textContent = '✕'; deleteButton.style.background = 'none'; deleteButton.style.border = 'none'; deleteButton.style.color = '#007aff'; deleteButton.style.cursor = 'pointer'; deleteButton.style.fontSize = '12px'; deleteButton.style.padding = '0'; deleteButton.style.marginLeft = '3px'; deleteButton.style.width = '20px'; deleteButton.style.height = '20px'; deleteButton.onclick = () => { newUserDiv.remove(); updateUserOptions(); // 更新其他下拉框中的选项 }; newUserSelect.addEventListener('change', updateUserOptions); newUserDiv.appendChild(newUserSelect); newUserDiv.appendChild(deleteButton); userInputs.appendChild(newUserDiv); // 设置空白选项为默认选项 newUserSelect.selectedIndex = 0; } function updateUserOptions() { const selectedValues = Array.from(document.querySelectorAll('.user-select-container select')) .map(select => select.value); document.querySelectorAll('.user-select-container select').forEach(select => { const currentValue = select.value; select.innerHTML = ''; // 清空现有选项 // 添加一个默认的空白选项 const defaultOption = document.createElement('option'); defaultOption.value = ''; defaultOption.textContent = '请选择用户'; select.appendChild(defaultOption); fetch('http://${serverIP}:${serverPort}/api/admin/userInfoAll', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { data.data.forEach(user => { if (!selectedValues.includes(user.Username) || user.Username === currentValue) { if (user.Username !== 'admin') { // 过滤掉admin用户 const option = document.createElement('option'); option.value = user.Username; option.textContent = user.Username; select.appendChild(option); } } }); select.value = currentValue; }); }); } // 打开修改信息表单框 function modifyLicenseInfo() { const form = document.getElementById('modifyLicenseForm'); // 将选中的行数据填充到表单中 form.creator.value = selectedRowData.Creator; form.applicationDate.value = selectedRowData.ApplicationDate; form.associatedProject.value = selectedRowData.GlxmName; form.salesPerson.value = selectedRowData.SalesPerson; form.salesEmail.value = selectedRowData.SalesEmail; form.supportPerson.value = selectedRowData.SupportPerson; form.supportEmail.value = selectedRowData.SupportEmail; form.totalNodes.value = selectedRowData.TotalNodes; form.company.value = selectedRowData.Company; form.productName.value = selectedRowData.ProductName; form.version.value = selectedRowData.ProductVersion; form.nodeCount.value = selectedRowData.NodeCount; document.getElementById('modifyLicenseModal').style.display = 'block'; } // 保存修改后的数据 function saveLicenseChanges() { const form = document.getElementById('modifyLicenseForm'); const updatedData = { UniqueID: selectedRowData.UniqueID, Creator: form.creator.value, ApplicationDate: form.applicationDate.value, AssociatedProject: form.associatedProject.value, SalesPerson: form.salesPerson.value, SalesEmail: form.salesEmail.value, SupportPerson: form.supportPerson.value, SupportEmail: form.supportEmail.value, TotalNodes: parseInt(form.totalNodes.value, 10), // 将 TotalNodes 转换为整数 Company: form.company.value, ProductName: form.productName.value, Version: form.version.value, NodeCount: parseInt(form.nodeCount.value, 10), // 将 NodeCount 转换为整数 }; fetch(`http://${serverIP}:${serverPort}/api/admin/UpdateLicense`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(updatedData) }) .then(response => response.json()) .then(data => { if (data.success) { alert('License信息更新成功!'); // fetchApplications(LisOffset, pageSize); const startOffset = currentOffset; // 当前的起始位置 const endOffset = startOffset + itemsPerPage - 1; // 计算结束位置 fetchApplications(startOffset, endOffset); // 传入计算好的起始和结束位置 closeModal('modifyLicenseModal'); } else { alert('License信息更新失败:' + data.error); } }); } function updateUserOptions() { const selectedValues = Array.from(document.querySelectorAll('.user-select-container select')) .map(select => select.value); document.querySelectorAll('.user-select-container select').forEach(select => { const currentValue = select.value; // 保留当前选择值 select.innerHTML = ''; // 清空现有选项 fetch('http://${serverIP}:${serverPort}/api/admin/distributeLicenseByUserInfo', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { data.data.forEach(user => { // 保留当前值,并排除已经在其他下拉框中选中的值 if (!selectedValues.includes(user.Username) || user.Username === currentValue) { const option = document.createElement('option'); option.value = user.Username; option.textContent = user.Username; if (user.Username === currentValue) { option.selected = true; // 保持当前选择 } select.appendChild(option); } }); }); }); } //lic分发给用户 与邮件 function sendEmail() { console.log('Send button clicked'); const emailInputs = document.querySelectorAll('.email-modal-input[type="text"]'); let emails = Array.from(emailInputs) .map(input => input.value.trim()) .filter(email => email && email.includes('@')) .join(','); const supportEmailChecked = document.getElementById('supportEmailCheckbox').checked; const salesEmailChecked = document.getElementById('salesEmailCheckbox').checked; const emailArray = emails ? [emails] : []; if (supportEmailChecked) { emailArray.push(document.getElementById('supportEmailCheckbox').value); } if (salesEmailChecked) { emailArray.push(document.getElementById('salesEmailCheckbox').value); } emails = emailArray.join(','); // if (!emails) { // alert('请至少选择一个邮箱地址。'); // return; // } console.log('Emails to send:', emails); const userInputs = document.querySelectorAll('select.email-modal-input'); console.log('userMap:', userMap); const users = Array.from(userInputs) .map(select => userMap[select.value].Account) .join(','); const userIds = Array.from(userInputs) .map(select => userMap[select.value].UniqueID) .join(','); const userNames = Array.from(userInputs) .map(select => userMap[select.value].Username); const operatorUniqueID = userMap[currentUserName].UniqueID; console.log('User IDs:', userIds); console.log('Users:', users); console.log(' selectedRowData.UniqueID:', selectedRowData.UniqueID); if (!userIds) { alert('请至少选择一个用户。'); return; } const requestData = { LicenseUniqueID: selectedRowData.UniqueID, Oa_request_id: selectedRowData.Oa_request_id, UserUniqueIDs: userIds.split(','), UserAccounts: users.split(','), Emails: emails, UserNames: userNames, OperatorUniqueID: operatorUniqueID }; console.log('requestData:', requestData); fetch('http://${serverIP}:${serverPort}/api/admin/distributeLicense', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }) .then(response => { console.log('Response received'); return response.json(); }) .then(data => { if (data.success) { alert('分发成功!'); closeModal('emailModal'); } else { // 检查是否有 error 字段,并提示用户详细的错误信息 const errorMessage = data.error || '分发失败。'; alert(`分发失败: ${errorMessage}`); } }) .catch(error => { console.error('Error occurred during email distribution:', error); alert('分发失败,请检查网络或后端服务。'); }); } function showDistributionHistory() { fetch('http://${serverIP}:${serverPort}/api/admin/GetlicenseRecord', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ uniqueID: selectedRowData.UniqueID, oa_request_id: selectedRowData.oa_request_id }) }) .then(response => response.json()) .then(data => { const distributionHistoryContent = document.getElementById('distributionHistoryContent'); const { license_record_to_user, license_record_to_emails } = data.data; // 确保 license_record_to_user 和 license_record_to_emails 存在并且是数组 const userRecords = Array.isArray(license_record_to_user) ? license_record_to_user : []; const emailRecords = Array.isArray(license_record_to_emails) ? license_record_to_emails : []; if (userRecords.length > 0 || emailRecords.length > 0) { const userHistoryHtml = userRecords.map(record => ` <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 10px; background-color: #f9f9f9;"> <p><strong>已转发给用户:</strong> ${record.user_account}</p> <p><strong>分发时间:</strong> ${new Date(record.up_time).toLocaleString()}</p> </div> `).join(''); const emailHistoryHtml = emailRecords.map(record => ` <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 10px; background-color: #f9f9f9;"> <p><strong>已发给邮箱:</strong> ${record.emails}</p> <p><strong>分发时间:</strong> ${new Date(record.up_time).toLocaleString()}</p> </div> `).join(''); distributionHistoryContent.innerHTML = userHistoryHtml + emailHistoryHtml; } else { distributionHistoryContent.innerHTML = `<p>没有分发历史记录。</p>`; } // 显示模态框 const distributionHistoryModal = document.getElementById('distributionHistoryModal'); distributionHistoryModal.style.display = 'block'; }); } function showMoreUserInfo() { const extraInfoContent = document.getElementById('extraInfoContent'); extraInfoContent.innerHTML = ` <p><strong>用户名:</strong> ${selectedRowData.Username}</p> <p><strong>电话:</strong> ${selectedRowData.Telephone}</p> <p><strong>邮箱:</strong> ${selectedRowData.Email}</p> <p><strong>权限:</strong> ${selectedRowData.Role}</p> `; document.getElementById('extraInfoModal').style.display = 'block'; } function modifyUser() { const userInfoContent = document.getElementById('extraInfoContent'); userInfoContent.innerHTML = ` <p><strong>用户名:</strong> ${selectedRowData.Username}</p> <p><strong>电话:</strong> ${selectedRowData.Telephone}</p> <p><strong>邮箱:</strong> ${selectedRowData.Email}</p> <p><strong>权限:</strong> ${selectedRowData.Role}</p> <button onclick="showEditUserForm()">编辑用户信息</button> `; document.getElementById('extraInfoModal').style.display = 'block'; } //查看额外信息 function showExtraInfo() { const extraInfoContent = document.getElementById('extraInfoContent'); // 清空之前的内容 extraInfoContent.innerHTML = ''; // 使用预定义的字段名和中文翻译 const fieldTranslations = { id: "ID", user_id: "用户ID", up_user: "上传用户", up_time: "上传时间", del_time: "删除时间", License1: "License 1", License2: "License 2", LicenseFlage: "License 状态", UniqueID: "唯一标识符", Creator: "创建人", ApplicationDate: "申请日期", AssociatedProject: "关联项目", SalesPerson: "销售人员", SalesEmail: "销售邮箱", SupportPerson: "支持人员", SupportEmail: "支持邮箱", TotalNodes: "总节点数", Company: "公司", ProductName: "产品名称", Version: "版本", NodeCount: "节点数", Processor: "处理器", OperatingSystem: "操作系统", MasterMacAddress: "主MAC地址", SecondaryMasterMacAddress: "备用主MAC地址" }; // 使用指定的字段进行展示 const fieldsToShow = [ "id", "user_id", "up_user", "up_time", "del_time", "License1", "License2", "LicenseFlage", "UniqueID", "Creator", "ApplicationDate", "AssociatedProject", "SalesPerson", "SalesEmail", "SupportPerson", "SupportEmail", "TotalNodes", "Company", "ProductName", "Version", "NodeCount", "Processor", "OperatingSystem", "MasterMacAddress", "SecondaryMasterMacAddress" ]; fieldsToShow.forEach(key => { if (selectedRowData.hasOwnProperty(key)) { let value = selectedRowData[key]; // 特殊处理 up_time 和 del_time if (key === 'up_time' || key === 'del_time') { if (value.Valid) { value = new Date(value.Time).toLocaleString(); // 格式化日期时间 } else { value = '无'; } } // 处理 License1 和 License2,提取字符串字段 if (key === 'License1' || key === 'License2') { // 假设 License 对象包含一个名为 'Details' 的字符串字段 value = value.String || '[无数据]'; } // 处理 MasterMacAddress 和 SecondaryMasterMacAddress,提取字符串字段 // if (key === 'MasterMacAddress' || key === 'SecondaryMasterMacAddress') { // // 假设 License 对象包含一个名为 'Details' 的字符串字段 // value = value.String || '[无数据]'; // } const infoElement = document.createElement('p'); infoElement.innerHTML = `<strong>${fieldTranslations[key]}:</strong> ${value}`; extraInfoContent.appendChild(infoElement); } }); // 显示 modal document.getElementById('extraInfoModal').style.display = 'block'; } function showRoleManagement() { document.getElementById('table-container').style.display = 'none'; document.getElementById('user-management').style.display = 'none'; // 隐藏用户管理页面 document.getElementById('role-management').style.display = 'block';; fetchRoles(); } function fetchRoles() { fetch('http://${serverIP}:${serverPort}/api/admin/GetRoles', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ Name: " " }) // 发送空的 Name 参数 }) .then(response => response.json()) .then(data => { const roleContainer = document.getElementById('roles-container'); roleContainer.innerHTML = ''; // 清空之前的内容 const permissionMap = { 'generate_license': '生成许可证', 'upload_license': '上传许可证', 'read_license': '读取许可证', 'read_license_record': '读取许可证分发记录', 'update_license': '修改许可证', 'delete_license': '删除许可证', 'dispat_license': '分发许可证', 'create_user': '创建用户', 'read_user': '读取用户', 'update_user': '更新用户', 'delete_user': '删除用户', 'create_role': '创建角色', 'delete_role': '删除角色', 'update_role': '更新角色', 'get_role': '获取角色' }; // 检查用户是否有 create_role 权限 const hasCreateRolePermission = userPermissions.includes('create_role'); // 如果有权限则显示“创建角色”按钮 if (hasCreateRolePermission) { document.getElementById('createRoleButton').style.display = 'block'; } else { document.getElementById('createRoleButton').style.display = 'none'; } // 处理置顶角色和其他角色的渲染(代码不变) const topRoles = ['admin', 'guest', 'supportRole']; topRoles.forEach(role => { if (data.data[role]) { renderRole(roleContainer, data.data[role], permissionMap, true); } }); Object.keys(data.data).forEach(role => { if (!topRoles.includes(role)) { renderRole(roleContainer, data.data[role], permissionMap, false); } }); }); } function renderRole(container, roleInfo, permissionMap, isTopRole) { const roleDiv = document.createElement('div'); roleDiv.className = 'role-item'; roleDiv.style.position = 'relative'; // 确保弹出菜单能够正确定位 if (isTopRole) { roleDiv.classList.add('top-role'); // 应用置顶角色的样式 } let permissions = roleInfo.Permissions.map(permission => permissionMap[permission]); let permissionsHtml = permissions.join(','); // 使用逗号分隔并合并为一行 roleDiv.innerHTML = ` <h3>${roleInfo.Name}</h3> <p>${permissionsHtml}</p> `; container.appendChild(roleDiv); // 添加事件监听器,处理点击和右键点击弹出菜单 roleDiv.addEventListener('click', function(event) { event.stopPropagation(); // 阻止事件冒泡 event.preventDefault(); // 阻止默认行为 showRoleActionMenu(event, roleInfo.Name); }); roleDiv.addEventListener('contextmenu', function(event) { event.preventDefault(); showRoleActionMenu(event, roleInfo.Name); }); } function showRoleActionMenu(event, roleName) { const existingMenu = document.getElementById('role-action-menu'); if (existingMenu) { existingMenu.remove(); } const menu = document.createElement('div'); menu.id = 'role-action-menu'; menu.style.position = 'absolute'; menu.style.top = `${event.clientY}px`; menu.style.left = `${event.clientX}px`; menu.style.backgroundColor = '#fff'; menu.style.border = '1px solid #ccc'; menu.style.borderRadius = '5px'; menu.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.2)'; menu.style.padding = '10px'; menu.style.zIndex = '1000'; const topRoles = ['admin', 'guest', 'support']; if (topRoles.includes(roleName)) { // 为 admin, guest, supportRole 设置灰色和不可点击样式 const disabledButton = document.createElement('button'); disabledButton.textContent = '不可操作'; disabledButton.style.display = 'block'; disabledButton.style.width = '100%'; disabledButton.style.padding = '10px 20px'; disabledButton.style.border = 'none'; disabledButton.style.borderRadius = '15px'; disabledButton.style.cursor = 'not-allowed'; disabledButton.style.backgroundColor = '#d3d3d3'; // 灰色背景 disabledButton.style.color = '#999'; // 灰色文字 menu.appendChild(disabledButton); } else { // 检查用户是否有 update_role 和 delete_role 权限 const hasUpdateRolePermission = userPermissions.includes('update_role'); const hasDeleteRolePermission = userPermissions.includes('delete_role'); // 创建和添加修改角色按钮 if (hasUpdateRolePermission) { const modifyButton = document.createElement('button'); modifyButton.textContent = '修改角色'; modifyButton.style.display = 'block'; modifyButton.style.marginBottom = '10px'; modifyButton.style.width = '100%'; modifyButton.style.padding = '10px 20px'; modifyButton.style.border = 'none'; modifyButton.style.borderRadius = '15px'; modifyButton.style.cursor = 'pointer'; modifyButton.style.transition = 'background-color 0.3s, color 0.3s'; modifyButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)'; modifyButton.style.backgroundColor = '#007aff'; modifyButton.style.color = '#fff'; modifyButton.addEventListener('mouseenter', function () { modifyButton.style.backgroundColor = '#005bb5'; }); modifyButton.addEventListener('mouseleave', function () { modifyButton.style.backgroundColor = '#007aff'; }); modifyButton.addEventListener('click', function () { modifyRole(roleName); menu.remove(); // 点击按钮后,关闭菜单栏 }); menu.appendChild(modifyButton); } // 创建和添加删除角色按钮 if (hasDeleteRolePermission) { const deleteButton = document.createElement('button'); deleteButton.textContent = '删除角色'; deleteButton.style.display = 'block'; deleteButton.style.width = '100%'; deleteButton.style.padding = '10px 20px'; deleteButton.style.border = 'none'; deleteButton.style.borderRadius = '15px'; deleteButton.style.cursor = 'pointer'; deleteButton.style.transition = 'background-color 0.3s, color 0.3s'; deleteButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)'; deleteButton.style.backgroundColor = '#ff3b30'; deleteButton.style.color = '#fff'; deleteButton.addEventListener('mouseenter', function () { deleteButton.style.backgroundColor = '#c23321'; }); deleteButton.addEventListener('mouseleave', function () { deleteButton.style.backgroundColor = '#ff3b30'; }); deleteButton.addEventListener('click', function () { deleteRole(roleName); menu.remove(); // 点击按钮后,关闭菜单栏 }); menu.appendChild(deleteButton); } // 如果用户没有修改或删除权限,则显示没有选项的提示 if (!hasUpdateRolePermission && !hasDeleteRolePermission) { const noOption = document.createElement('div'); noOption.textContent = '没有可用的操作'; noOption.style.textAlign = 'center'; noOption.style.color = '#999'; menu.appendChild(noOption); } } document.body.appendChild(menu); document.addEventListener('click', function closeMenu(event) { if (!menu.contains(event.target)) { menu.remove(); document.removeEventListener('click', closeMenu); } }); } //修改角色信息 function modifyRole(roleName) { console.log(`modifyRole called with roleName: ${roleName}`); fetchRoleInfo(roleName, function(roleInfo) { console.log(`fetchRoleInfo returned:`, roleInfo); if (!roleInfo) { console.error('Role info is undefined or null'); return; } const extraInfoContent = document.getElementById('extraInfoContent'); if (!extraInfoContent) { console.error('Element with id "extraInfoContent" not found'); return; } extraInfoContent.innerHTML = ` <h3>修改角色: ${roleInfo.Name}</h3> <label for="roleName">角色名称:</label> <input type="text" id="roleName" value="${roleInfo.Name}" required><br><br> <label for="permissions">权限:</label><br> <div id="permissions"> <div> <input type="checkbox" id="license" name="permissions" value="license" onchange="toggleSubPermissions('license', this)"> <label for="license">许可证</label> <div id="licenseSubPermissions" style="margin-left: 20px;"> <input type="checkbox" id="generate_license" name="permissions" value="generate_license"> <label for="generate_license">生成许可证</label><br> <input type="checkbox" id="upload_license" name="permissions" value="upload_license"> <label for="upload_license">上传许可证</label><br> <input type="checkbox" id="read_license" name="permissions" value="read_license"> <label for="read_license">读取许可证</label><br> <input type="checkbox" id="update_license" name="permissions" value="update_license"> <label for="update_license">更新许可证</label><br> <input type="checkbox" id="delete_license" name="permissions" value="delete_license"> <label for="delete_license">删除许可证</label><br> </div> </div> <div> <input type="checkbox" id="user" name="permissions" value="user" onchange="toggleSubPermissions('user', this)"> <label for="user">用户</label> <div id="userSubPermissions" style="margin-left: 20px;"> <input type="checkbox" id="create_user" name="permissions" value="create_user"> <label for="create_user">创建用户</label><br> <input type="checkbox" id="read_user" name="permissions" value="read_user"> <label for="read_user">读取用户</label><br> <input type="checkbox" id="update_user" name="permissions" value="update_user"> <label for="update_user">更新用户</label><br> <input type="checkbox" id="delete_user" name="permissions" value="delete_user"> <label for="delete_user">删除用户</label><br> </div> </div> <div> <input type="checkbox" id="role" name="permissions" value="role" onchange="toggleSubPermissions('role', this)"> <label for="role">角色</label> <div id="roleSubPermissions" style="margin-left: 20px;"> <input type="checkbox" id="create_role" name="permissions" value="create_role"> <label for="create_role">创建角色</label><br> <input type="checkbox" id="delete_role" name="permissions" value="delete_role"> <label for="delete_role">删除角色</label><br> <input type="checkbox" id="update_role" name="permissions" value="update_role"> <label for="update_role">更新角色</label><br> <input type="checkbox" id="get_role" name="permissions" value="get_role"> <label for="get_role">获取角色</label><br> </div> </div> </div><br><br> <button onclick="saveRoleChanges('${roleInfo.Id}')">保存</button> `; console.log('Form content added to extraInfoContent'); const checkboxes = document.querySelectorAll('#permissions input[type="checkbox"]'); // 遍历所有复选框 checkboxes.forEach(checkbox => { if (roleInfo.Permissions.includes(checkbox.value)) { checkbox.checked = true; // 如果当前权限在roleInfo.Permissions中,则勾选 } }); const extraInfoModal = document.getElementById('extraInfoModal'); if (!extraInfoModal) { console.error('Element with id "extraInfoModal" not found'); return; } extraInfoModal.style.display = 'block'; // 强制显示模态框 console.log('Modal should be visible now'); }); } function getCheckboxOptions(selectedPermissions) { const permissionMap = { 'generate_license': '生成许可证', 'upload_license': '上传许可证', 'read_license': '读取许可证', 'update_license': '修改许可证', 'delete_license': '删除许可证', 'dispat_license': '分发许可证', 'read_license_record': '读取许可证分发记录', // 'get_user_info': '获取用户信息', 'create_user': '创建用户', 'read_user': '读取用户', 'update_user': '更新用户', 'delete_user': '删除用户', 'create_role': '创建角色', 'delete_role': '删除角色', 'update_role': '更新角色', 'get_role': '获取角色' }; return Object.keys(permissionMap).map(permission => ` <div> <input type="checkbox" id="${permission}" name="permissions" value="${permission}" ${selectedPermissions.includes(permission) ? 'checked' : ''}> <label for="${permission}">${permissionMap[permission]}</label> </div> `).join(''); } function fetchRoleInfo(roleName, callback) { console.log(`fetchRoleInfo called with roleName: ${roleName}`); fetch('http://${serverIP}:${serverPort}/api/admin/GetRoles', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ Name: roleName }) }) .then(response => { console.log('fetchRoleInfo response received', response); return response.json(); }) .then(data => { console.log('fetchRoleInfo data received', data); // 直接从 data.data 获取角色信息 if (data && data.data) { console.log('Role info found:', data.data); callback(data.data); // 直接返回 data.data 而不是 data.data[roleName] } else { console.error('Role not found or unexpected data structure', data); callback(null); // 如果角色信息未找到,返回 null } }) .catch(error => { console.error('Error in fetchRoleInfo:', error); callback(null); // 捕获异常情况 }); } function getPermissionsOptions(selectedPermissions) { const permissionMap = { 'generate_license': '生成许可证', 'upload_license': '上传许可证', 'read_license': '读取许可证', 'update_license': '修改许可证', 'delete_license': '删除许可证', 'dispat_license': '分发许可证', 'read_license_record': '读取许可证分发记录', //'get_user_info': '获取用户信息', 'create_user': '创建用户', 'read_user': '读取用户', 'update_user': '更新用户', 'delete_user': '删除用户', 'create_role': '创建角色', 'delete_role': '删除角色', 'update_role': '更新角色', 'get_role': '获取角色' }; return Object.keys(permissionMap).map(permission => ` <option value="${permission}" ${selectedPermissions.includes(permission) ? 'selected' : ''}> ${permissionMap[permission]} </option> `).join(''); } function saveRoleChanges(roleId) { const updatedRoleName = document.getElementById('roleName').value.trim(); const selectedPermissions = Array.from(document.querySelectorAll('#permissions input[type="checkbox"]:checked')) .map(checkbox => checkbox.value) .filter(value => !['license', 'user', 'role'].includes(value)); // 过滤掉一级分类 if (!updatedRoleName) { alert('角色名称不能为空!'); return; } const updateRole = { Id: parseInt(roleId, 10), // 确保 roleId 被传递并转换为整数 Name: updatedRoleName, Permissions: selectedPermissions }; fetch('http://${serverIP}:${serverPort}/api/admin/UpdateRole', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(updateRole) }) .then(response => response.json()) .then(data => { if (data.success) { alert('角色更新成功!'); fetchRoles(); // 刷新角色列表 closeModal('extraInfoModal'); // 关闭信息栏 } else { alert('角色更新失败:' + data.error); } }); } //删除角色 function deleteRole(roleName) { console.log(`deleteRole called for role: ${roleName}`); const confirmed = confirm(`确认删除角色: ${roleName} 吗?`); if (!confirmed) { return; } fetch('http://${serverIP}:${serverPort}/api/admin/DeleteRole', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: roleName // 将角色名称传递给后端 }) }) .then(response => response.json()) .then(data => { if (data.success) { alert('角色删除成功!'); fetchRoles(); // 刷新角色列表 } else { alert('角色删除失败:' + data.error); } }) .catch(error => { console.error('Error deleting role:', error); alert('删除角色时发生错误,请稍后再试。'); }); } document.getElementById('createRoleButton').addEventListener('click', function() { const extraInfoContent = document.getElementById('extraInfoContent'); extraInfoContent.innerHTML = ` <h3>创建新角色</h3> <label for="newRoleName">角色名称:</label> <input type="text" id="newRoleName" required><br><br> <label for="newPermissions">权限:</label><br> <div id="newPermissions"> <div> <input type="checkbox" id="license" name="permissions" value="license" onchange="toggleSubPermissions('license', this)"> <label for="license">许可证</label> <div id="licenseSubPermissions" style="margin-left: 20px;"> <input type="checkbox" id="generate_license" name="permissions" value="generate_license"> <label for="generate_license">生成许可证</label><br> <input type="checkbox" id="upload_license" name="permissions" value="upload_license"> <label for="upload_license">上传许可证</label><br> <input type="checkbox" id="read_license" name="permissions" value="read_license"> <label for="read_license">读取许可证</label><br> <input type="checkbox" id="update_license" name="permissions" value="update_license"> <label for="update_license">更新许可证</label><br> <input type="checkbox" id="delete_license" name="permissions" value="delete_license"> <label for="delete_license">删除许可证</label><br> </div> </div> <div> <input type="checkbox" id="user" name="permissions" value="user" onchange="toggleSubPermissions('user', this)"> <label for="user">用户</label> <div id="userSubPermissions" style="margin-left: 20px;"> <input type="checkbox" id="create_user" name="permissions" value="create_user"> <label for="create_user">创建用户</label><br> <input type="checkbox" id="read_user" name="permissions" value="read_user"> <label for="read_user">读取用户</label><br> <input type="checkbox" id="update_user" name="permissions" value="update_user"> <label for="update_user">更新用户</label><br> <input type="checkbox" id="delete_user" name="permissions" value="delete_user"> <label for="delete_user">删除用户</label><br> </div> </div> <div> <input type="checkbox" id="role" name="permissions" value="role" onchange="toggleSubPermissions('role', this)"> <label for="role">角色</label> <div id="roleSubPermissions" style="margin-left: 20px;"> <input type="checkbox" id="create_role" name="permissions" value="create_role"> <label for="create_role">创建角色</label><br> <input type="checkbox" id="delete_role" name="permissions" value="delete_role"> <label for="delete_role">删除角色</label><br> <input type="checkbox" id="update_role" name="permissions" value="update_role"> <label for="update_role">更新角色</label><br> <input type="checkbox" id="get_role" name="permissions" value="get_role"> <label for="get_role">获取角色</label><br> </div> </div> </div><br><br> <button onclick="createNewRole()">创建</button> </div> `; document.getElementById('extraInfoModal').style.display = 'block'; }); function toggleSubPermissions(category, checkbox) { const subPermissions = document.querySelectorAll(`#${category}SubPermissions input[type="checkbox"]`); subPermissions.forEach(subCheckbox => { subCheckbox.checked = checkbox.checked; }); } function createNewRole() { const newRoleName = document.getElementById('newRoleName').value.trim(); const selectedPermissions = Array.from(document.querySelectorAll('#newPermissions input[type="checkbox"]:checked')) .map(checkbox => checkbox.value) .filter(value => !['license', 'user', 'role'].includes(value)); // 过滤掉一级分类 if (!newRoleName) { alert('角色名称不能为空!'); return; } const newRole = { Name: newRoleName, Permissions: selectedPermissions }; fetch('http://${serverIP}:${serverPort}/api/admin/CreateRole', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(newRole) }) .then(response => response.json()) .then(data => { if (data.success) { alert('角色创建成功!'); fetchRoles(); // 刷新角色列表 closeModal('extraInfoModal'); // 关闭信息栏 } else { alert('角色创建失败:' + data.error); } }); } //显示用户信息 function showEditUserForm() { const extraInfoContent = document.getElementById('extraInfoContent'); // 清空之前的内容 extraInfoContent.innerHTML = ''; // 创建表单 const form = document.createElement('form'); form.id = 'editUserForm'; form.style.width = '400px'; // 增加表单宽度 form.innerHTML = ` <div style="display: flex; align-items: center; margin-bottom: 15px;"> <label for="username" style="flex: 0 0 80px;">用户名:</label> <input type="text" id="username" name="username" value="${selectedRowData.Username}" style="flex: 1;" required> </div> <div style="display: flex; align-items: center; margin-bottom: 15px;"> <label for="telephone" style="flex: 0 0 80px;">电话:</label> <input type="text" id="telephone" name="telephone" value="${selectedRowData.Telephone}" style="flex: 1;" required> </div> <div style="display: flex; align-items: center; margin-bottom: 15px;"> <label for="email" style="flex: 0 0 80px;">邮箱:</label> <input type="email" id="email" name="email" value="${selectedRowData.Email}" style="flex: 1;" required> </div> `; // 检查用户是否有 'update_role' 权限,如果有,则显示权限选择框 if (userPermissions.includes('update_role')) { const roleSelectDiv = document.createElement('div'); roleSelectDiv.style = 'display: flex; align-items: center; margin-bottom: 15px;'; roleSelectDiv.innerHTML = ` <label for="role" style="flex: 0 0 80px;">权限:</label> <select id="role" name="role" style="flex: 1;" required></select> `; form.appendChild(roleSelectDiv); // 获取角色列表并填充到选择框中 fetch('http://${serverIP}:${serverPort}/api/admin/GetRoleNames', { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { const roleSelect = document.getElementById('role'); data.roles.forEach(role => { const option = document.createElement('option'); option.value = role; option.textContent = role; if (selectedRowData.Role === role) { option.selected = true; } roleSelect.appendChild(option); }); }) .catch(error => console.error('获取角色列表时出错:', error)); } // 将表单添加到弹出框内容中 extraInfoContent.appendChild(form); // 添加保存按钮 const saveButton = document.createElement('button'); saveButton.type = 'button'; saveButton.onclick = saveUserChanges; saveButton.style = 'width: 100%; background-color: #007bff; color: white; border: none; padding: 10px; border-radius: 5px;'; saveButton.textContent = '保存'; form.appendChild(saveButton); } function saveUserChanges() { const form = document.getElementById('editUserForm'); const formData = new FormData(form); const updatedUser = { Username: formData.get('username'), Telephone: formData.get('telephone'), Email: formData.get('email'), Role: formData.get('role') }; fetch(`http://${serverIP}:${serverPort}/api/admin/updateUser`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ ...updatedUser, Id: selectedRowData.Id }) }) .then(response => response.json()) .then(data => { if (data.success) { alert('用户信息更新成功!'); fetchUsers(); closeModal('extraInfoModal'); } else { alert('用户信息更新失败:' + data.error); } }); } //用户个人信息 function toggleUserInfo() { const userModal = document.getElementById('userModal'); const userButton = document.getElementById('username'); const rect = userButton.getBoundingClientRect(); const modalWidth = 300; // 信息栏的宽度 const windowWidth = window.innerWidth; // 浏览器窗口的宽度 if (userModal.style.display === 'none' || userModal.style.display === '') { fetch(`http://${serverIP}:${serverPort}/api/admin/userInfo`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { const userInfoContent = document.getElementById('userInfoContent'); let power; switch (data.data.Role) { case 'admin': power = '至高无上的主'; break; case 'supportRole': power = '运维'; break; case 'guest': power = '访客'; break; default: power = data.data.Role; } userInfoContent.innerHTML = ` <h2> 个人信息</h2> <div class="apple-modal-content"> <p class="apple-modal-text"><strong>用户名:</strong> ${data.data.Username}</p> <p class="apple-modal-text"><strong>账号:</strong> ${data.data.Account}</p> <p class="apple-modal-text"><strong>邮箱:</strong> ${data.data.Email}</p> <p class="apple-modal-text"><strong>电话:</strong> ${data.data.Telephone}</p> <p class="apple-modal-text"><strong>权限:</strong> ${power}</p> </div> `; // 设置模态框位置 userModal.style.top = `${rect.bottom + window.scrollY + 10}px`; const leftPosition = rect.right + window.scrollX + 20; // 右侧位置 const rightEdge = leftPosition + modalWidth; if (rightEdge > windowWidth) { const leftEdge = rect.left + window.scrollX - modalWidth - 20; userModal.style.left = `${Math.max(20, leftEdge)}px`; } else { userModal.style.left = `${leftPosition}px`; } userModal.style.display = 'block'; userModal.style.opacity = '0'; // 先设置透明度为0 setTimeout(() => { userModal.style.opacity = '1'; // 然后慢慢显示 }, 0); // 延迟一帧显示 userModal.style.transition = 'opacity 0.3s ease, top 0.3s ease, left 0.3s ease'; // 添加全局点击监听器 document.addEventListener('click', handleClickOutsideModal); }); } else { closeUserInfo(); } } function closeUserInfo() { const userModal = document.getElementById('userModal'); userModal.style.opacity = '0'; // 先设置透明度为0 setTimeout(() => { userModal.style.display = 'none'; // 然后隐藏 }, 300); // 延迟0.3秒,等待过渡结束 // 移除全局点击监听器 document.removeEventListener('click', handleClickOutsideModal); } function closeUserInfo() { const userModal = document.getElementById('userModal'); userModal.style.opacity = '0'; // 先设置透明度为0 setTimeout(() => { userModal.style.display = 'none'; // 然后隐藏 }, 300); // 延迟0.3秒,等待过渡结束 // 移除全局点击监听器 document.removeEventListener('click', handleClickOutsideModal); } function handleClickOutsideModal(event) { const userModal = document.getElementById('userModal'); if (!userModal.contains(event.target) && event.target.id !== 'username') { closeUserInfo(); } } //用户退出 function logout() { localStorage.removeItem('Authorization'); window.location.href = '/'; } function showUserManagement() { document.getElementById('table-container').style.display = 'none'; document.getElementById('role-management').style.display = 'none'; // 隐藏角色管理页面 document.getElementById('user-management').style.display = 'block'; // 检查用户是否有 create_user 权限 const hasCreateUserPermission = userPermissions.includes('create_user'); // 获取添加用户按钮元素 const addUserButton = document.getElementById('addUserButton'); // 根据权限显示或隐藏添加用户按钮 if (hasCreateUserPermission) { addUserButton.style.display = 'block'; } else { addUserButton.style.display = 'none'; } // 加载用户列表 fetchUsers(); } function showTable() { document.getElementById('user-management').style.display = 'none'; document.getElementById('role-management').style.display = 'none'; // 隐藏角色管理页面 document.getElementById('table-container').style.display = 'block'; } function toggleSidebar() { const sidebar = document.getElementById('sidebar'); const content = document.getElementById('content'); sidebar.classList.toggle('hidden'); content.classList.toggle('expanded'); const toggleButton = document.querySelector('.toggle-sidebar'); if (sidebar.classList.contains('hidden')) { toggleButton.innerHTML = '>'; // 当侧边栏隐藏时,显示右箭头 } else { toggleButton.innerHTML = '<'; // 当侧边栏显示时,显示左箭头 } } function fetchUsername() { fetch(`http://${serverIP}:${serverPort}/api/admin/userInfo`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { document.getElementById('username').textContent = data.data.Username; currentUserRole = data.data.Role; // 存储当前用户的角色 currentUserName = data.data.Username // 使用获取到的角色,调用获取权限的接口 fetchPermissionsByRole(currentUserRole) .then(() => { //fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications const startOffset = currentOffset; // 当前的起始位置 const endOffset = startOffset + itemsPerPage - 1; // 计算结束位置 fetchApplications(startOffset, endOffset); // 传入计算好的起始和结束位置 // 检查用户是否有 upload_license 权限 const hasUploadLicensePermission = userPermissions.includes('upload_license'); // 获取上传按钮元素 const uploadButton = document.querySelector('.upload-button'); // 根据权限显示或隐藏上传按钮 // if (hasUploadLicensePermission) { // uploadButton.style.display = 'inline-block'; // 显示按钮 // } else { // uploadButton.style.display = 'none'; // 隐藏按钮 // } // 是否生成主动抓取lic按钮 checkCaptureLicensePermission(); // 检查是否有 capture_license_once_to_db 权限 }); }); } function fetchPermissionsByRole(role) { return fetch(`http://${serverIP}:${serverPort}/api/admin/GetSelfRoles`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: role }) }) .then(response => response.json()) .then(data => { userPermissions = data.data.Permissions; // 获取用户的权限数组 console.log('userPermissions:', userPermissions); // 定义权限类别 const licensePermissions = ['upload_license', 'read_license']; const userPermissionsCheck = [ 'create_user', 'read_user', 'update_user', 'delete_user']; const rolePermissions = ['create_role', 'delete_role', 'update_role', 'get_role']; const hasLicenseAccess = licensePermissions.some(permission => userPermissions.includes(permission)); const hasUserManagementAccess = userPermissionsCheck.some(permission => userPermissions.includes(permission)); const hasRoleManagementAccess = rolePermissions.some(permission => userPermissions.includes(permission)); // 根据权限渲染菜单并显示初始页面 renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, hasRoleManagementAccess); }); } function renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, hasRoleManagementAccess) { const sidebar = document.querySelector('.sidebar'); // 清空现有菜单项 sidebar.innerHTML = ''; let initialPageShown = false; // 动态添加菜单项并确定初始显示的页面 if (hasLicenseAccess) { const licenseButton = document.createElement('button'); licenseButton.textContent = 'License 管理'; licenseButton.onclick = showTable; sidebar.appendChild(licenseButton); if (!initialPageShown) { showTable(); // 如果有License权限,先显示License页面 initialPageShown = true; } } if (hasUserManagementAccess) { const userManagementButton = document.createElement('button'); userManagementButton.textContent = '用户管理'; userManagementButton.onclick = showUserManagement; sidebar.appendChild(userManagementButton); if (!initialPageShown) { showUserManagement(); // 如果没有License权限,但有用户管理权限,显示用户管理页面 initialPageShown = true; } } if (hasRoleManagementAccess) { const roleManagementButton = document.createElement('button'); roleManagementButton.textContent = '角色管理'; roleManagementButton.onclick = showRoleManagement; sidebar.appendChild(roleManagementButton); if (!initialPageShown) { showRoleManagement(); // 如果没有License和用户管理权限,但有角色管理权限,显示角色管理页面 initialPageShown = true; } } if (!initialPageShown && sidebar.firstChild) { sidebar.firstChild.click(); // 如果没有优先的权限页面,则显示菜单中的第一个页面 } } // 添加到每个模态框的 JavaScript 部分 document.addEventListener('DOMContentLoaded', function() { // 获取所有模态框 const modals = document.querySelectorAll('.modal'); // 为每个模态框添加点击事件监听器 modals.forEach(modal => { modal.addEventListener('click', function(event) { // 如果点击的是模态框背景而不是模态框内容,关闭模态框 if (event.target === modal) { modal.style.display = 'none'; } }); }); }); // 页面初始化时调用 fetchUsername 函数 fetchUsername(); //fetchApplications(currentPage, pageSize); </script> </body> </html>