在管理中新增系统日志页面
This commit is contained in:
parent
59f4a25172
commit
9f393ce709
Binary file not shown.
BIN
XNSimHtml/assets/icons/png/file-text.png
Normal file
BIN
XNSimHtml/assets/icons/png/file-text.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
BIN
XNSimHtml/assets/icons/png/file-text_b.png
Normal file
BIN
XNSimHtml/assets/icons/png/file-text_b.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
@ -141,6 +141,9 @@ class ContentArea extends HTMLElement {
|
|||||||
case 'users':
|
case 'users':
|
||||||
contentElement = document.createElement('user-management');
|
contentElement = document.createElement('user-management');
|
||||||
break;
|
break;
|
||||||
|
case 'system-log':
|
||||||
|
contentElement = document.createElement('system-log');
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
contentElement = document.createElement('div');
|
contentElement = document.createElement('div');
|
||||||
contentElement.textContent = '正在开发中...';
|
contentElement.textContent = '正在开发中...';
|
||||||
|
@ -97,8 +97,8 @@ class MainToolbar extends HTMLElement {
|
|||||||
<span>监控</span>
|
<span>监控</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tool-item" data-tool="system" id="systemManagement">
|
<div class="tool-item" data-tool="system" id="systemManagement">
|
||||||
<img src="assets/icons/png/cogs.png" alt="系统管理" class="icon">
|
<img src="assets/icons/png/cogs.png" alt="管理" class="icon">
|
||||||
<span>系统管理</span>
|
<span>管理</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -237,6 +237,10 @@ class SubToolbar extends HTMLElement {
|
|||||||
<img src="assets/icons/png/user.png" alt="个人中心" class="icon">
|
<img src="assets/icons/png/user.png" alt="个人中心" class="icon">
|
||||||
个人中心
|
个人中心
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sub-item" data-icon="file-text">
|
||||||
|
<img src="assets/icons/png/file-text.png" alt="系统日志" class="icon">
|
||||||
|
系统日志
|
||||||
|
</div>
|
||||||
<div class="sub-item admin-only" data-icon="users">
|
<div class="sub-item admin-only" data-icon="users">
|
||||||
<img src="assets/icons/png/users.png" alt="用户管理" class="icon">
|
<img src="assets/icons/png/users.png" alt="用户管理" class="icon">
|
||||||
用户管理
|
用户管理
|
||||||
@ -308,7 +312,7 @@ class SubToolbar extends HTMLElement {
|
|||||||
'config': { icon: 'sliders', text: '配置' },
|
'config': { icon: 'sliders', text: '配置' },
|
||||||
'run': { icon: 'play', text: '运行' },
|
'run': { icon: 'play', text: '运行' },
|
||||||
'monitor': { icon: 'chart', text: '监控' },
|
'monitor': { icon: 'chart', text: '监控' },
|
||||||
'system': { icon: 'cogs', text: '系统管理' }
|
'system': { icon: 'cogs', text: '管理' }
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentTool = toolIcons[this._currentTool] || toolIcons['home'];
|
const currentTool = toolIcons[this._currentTool] || toolIcons['home'];
|
||||||
|
405
XNSimHtml/components/system-log.js
Normal file
405
XNSimHtml/components/system-log.js
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
class SystemLog extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.render();
|
||||||
|
this.addEventListeners();
|
||||||
|
this.loadLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.shadowRoot.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px 8px 36px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input:focus {
|
||||||
|
border-color: #409eff;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-select {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
background: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-select:focus {
|
||||||
|
border-color: #409eff;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: #409eff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: #66b1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-default {
|
||||||
|
background: #f4f4f5;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-default:hover {
|
||||||
|
background: #e9e9eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-content {
|
||||||
|
flex: 1;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 180px 120px 120px 1fr;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 180px 120px 120px 1fr;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-item:hover {
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-level {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-info {
|
||||||
|
background: #e1f3d8;
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-warning {
|
||||||
|
background: #fdf6ec;
|
||||||
|
color: #e6a23c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-error {
|
||||||
|
background: #fef0f0;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-debug {
|
||||||
|
background: #f4f4f5;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 16px;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #fff;
|
||||||
|
color: #606266;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn:hover {
|
||||||
|
color: #409eff;
|
||||||
|
border-color: #c6e2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn.active {
|
||||||
|
background: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn:disabled {
|
||||||
|
background: #f5f7fa;
|
||||||
|
color: #c0c4cc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="log-container">
|
||||||
|
<div class="toolbar">
|
||||||
|
<div class="search-box">
|
||||||
|
<img src="assets/icons/png/search_b.png" alt="搜索" class="search-icon">
|
||||||
|
<input type="text" placeholder="搜索日志内容...">
|
||||||
|
</div>
|
||||||
|
<div class="filter-group">
|
||||||
|
<select class="filter-select" id="levelFilter">
|
||||||
|
<option value="">所有级别</option>
|
||||||
|
<option value="info">信息</option>
|
||||||
|
<option value="warning">警告</option>
|
||||||
|
<option value="error">错误</option>
|
||||||
|
<option value="debug">调试</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-select" id="timeFilter">
|
||||||
|
<option value="1h">最近1小时</option>
|
||||||
|
<option value="6h">最近6小时</option>
|
||||||
|
<option value="24h">最近24小时</option>
|
||||||
|
<option value="7d">最近7天</option>
|
||||||
|
<option value="30d">最近30天</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button class="btn btn-default" id="refreshBtn">
|
||||||
|
<img src="assets/icons/png/refresh.png" alt="刷新" class="icon-small">
|
||||||
|
刷新
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary" id="exportBtn">
|
||||||
|
<img src="assets/icons/png/download.png" alt="导出" class="icon-small">
|
||||||
|
导出
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="log-content">
|
||||||
|
<div class="log-header">
|
||||||
|
<div>时间</div>
|
||||||
|
<div>级别</div>
|
||||||
|
<div>来源</div>
|
||||||
|
<div>内容</div>
|
||||||
|
</div>
|
||||||
|
<div class="log-list" id="logList">
|
||||||
|
<!-- 日志内容将通过JavaScript动态添加 -->
|
||||||
|
</div>
|
||||||
|
<div class="pagination">
|
||||||
|
<button class="page-btn" id="prevPage" disabled>上一页</button>
|
||||||
|
<button class="page-btn active">1</button>
|
||||||
|
<button class="page-btn">2</button>
|
||||||
|
<button class="page-btn">3</button>
|
||||||
|
<button class="page-btn" id="nextPage">下一页</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListeners() {
|
||||||
|
// 搜索框事件
|
||||||
|
const searchInput = this.shadowRoot.querySelector('.search-box input');
|
||||||
|
searchInput.addEventListener('input', this.debounce(() => {
|
||||||
|
this.filterLogs();
|
||||||
|
}, 300));
|
||||||
|
|
||||||
|
// 级别筛选事件
|
||||||
|
const levelFilter = this.shadowRoot.querySelector('#levelFilter');
|
||||||
|
levelFilter.addEventListener('change', () => {
|
||||||
|
this.filterLogs();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 时间筛选事件
|
||||||
|
const timeFilter = this.shadowRoot.querySelector('#timeFilter');
|
||||||
|
timeFilter.addEventListener('change', () => {
|
||||||
|
this.filterLogs();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 刷新按钮事件
|
||||||
|
const refreshBtn = this.shadowRoot.querySelector('#refreshBtn');
|
||||||
|
refreshBtn.addEventListener('click', () => {
|
||||||
|
this.loadLogs();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导出按钮事件
|
||||||
|
const exportBtn = this.shadowRoot.querySelector('#exportBtn');
|
||||||
|
exportBtn.addEventListener('click', () => {
|
||||||
|
this.exportLogs();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分页按钮事件
|
||||||
|
const prevPage = this.shadowRoot.querySelector('#prevPage');
|
||||||
|
const nextPage = this.shadowRoot.querySelector('#nextPage');
|
||||||
|
prevPage.addEventListener('click', () => {
|
||||||
|
this.changePage(-1);
|
||||||
|
});
|
||||||
|
nextPage.addEventListener('click', () => {
|
||||||
|
this.changePage(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadLogs() {
|
||||||
|
try {
|
||||||
|
// 这里应该调用后端API获取日志数据
|
||||||
|
// 示例数据
|
||||||
|
const logs = [
|
||||||
|
{
|
||||||
|
timestamp: '2024-03-20 10:00:00',
|
||||||
|
level: 'info',
|
||||||
|
source: '系统',
|
||||||
|
content: '系统启动成功'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamp: '2024-03-20 10:01:00',
|
||||||
|
level: 'warning',
|
||||||
|
source: '数据库',
|
||||||
|
content: '数据库连接池接近最大连接数'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamp: '2024-03-20 10:02:00',
|
||||||
|
level: 'error',
|
||||||
|
source: 'API',
|
||||||
|
content: 'API请求超时'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
this.renderLogs(logs);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载日志失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLogs(logs) {
|
||||||
|
const logList = this.shadowRoot.querySelector('#logList');
|
||||||
|
logList.innerHTML = logs.map(log => `
|
||||||
|
<div class="log-item">
|
||||||
|
<div>${log.timestamp}</div>
|
||||||
|
<div><span class="log-level level-${log.level}">${this.getLevelText(log.level)}</span></div>
|
||||||
|
<div>${log.source}</div>
|
||||||
|
<div>${log.content}</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
getLevelText(level) {
|
||||||
|
const levelMap = {
|
||||||
|
'info': '信息',
|
||||||
|
'warning': '警告',
|
||||||
|
'error': '错误',
|
||||||
|
'debug': '调试'
|
||||||
|
};
|
||||||
|
return levelMap[level] || level;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterLogs() {
|
||||||
|
const searchText = this.shadowRoot.querySelector('.search-box input').value.toLowerCase();
|
||||||
|
const levelFilter = this.shadowRoot.querySelector('#levelFilter').value;
|
||||||
|
const timeFilter = this.shadowRoot.querySelector('#timeFilter').value;
|
||||||
|
|
||||||
|
// 这里应该根据筛选条件调用后端API获取过滤后的日志
|
||||||
|
this.loadLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
exportLogs() {
|
||||||
|
// 实现日志导出功能
|
||||||
|
console.log('导出日志');
|
||||||
|
}
|
||||||
|
|
||||||
|
changePage(delta) {
|
||||||
|
// 实现分页功能
|
||||||
|
console.log('切换页面:', delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
debounce(func, wait) {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('system-log', SystemLog);
|
@ -17,6 +17,7 @@
|
|||||||
<script src="components/run-log.js"></script>
|
<script src="components/run-log.js"></script>
|
||||||
<script src="components/system-info.js"></script>
|
<script src="components/system-info.js"></script>
|
||||||
<script src="components/help-component.js"></script>
|
<script src="components/help-component.js"></script>
|
||||||
|
<script src="components/system-log.js"></script>
|
||||||
<script src="components/run-env-config.js" type="module"></script>
|
<script src="components/run-env-config.js" type="module"></script>
|
||||||
<script src="components/model-config.js" type="module"></script>
|
<script src="components/model-config.js" type="module"></script>
|
||||||
<script src="components/service-config.js" type="module"></script>
|
<script src="components/service-config.js" type="module"></script>
|
||||||
@ -323,6 +324,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理系统日志标签页
|
||||||
|
if (title === '系统日志') {
|
||||||
|
const id = 'system-log';
|
||||||
|
tabsContainer.createTab(id, title, icon, parentText, parentTool);
|
||||||
|
contentArea.loadContent(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 处理帮助标签页
|
// 处理帮助标签页
|
||||||
if (title === '帮助') {
|
if (title === '帮助') {
|
||||||
const id = 'help';
|
const id = 'help';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user