gohttp/adminui/js/app.js

525 lines
19 KiB
JavaScript

// http_server_management_console/frontend/js/app.js
new Vue({
el: '#app',
data() {
return {
serverConfig: JSON.parse(localStorage.getItem('serverConfig')) || {
sites: [
{
id: Date.now(),
name: '示例网站',
domain: 'example.com',
port: 8080,
ssl: false,
collapsed: false,
routes: [
{
path: '/static',
type: 'static',
target: '静态资源'
},
{
path: '/api',
type: 'proxy',
target: 'http://backend:3000'
}
]
}
]
},
logs: JSON.parse(localStorage.getItem('serverLogs')) || [
{ timestamp: '2025-05-06 23:13:22', message: '添加了路由配置 /api → http://backend:3000', type: 'success' },
{ timestamp: '2025-05-06 23:12:15', message: '修改了网站端口 8080 → 8443', type: 'warning' },
{ timestamp: '2025-05-06 23:10:07', message: '创建了网站配置 example.com', type: 'info' }
],
requestCount: 0,
goroutineCount: 10,
filterType: 'all',
searchQuery: '',
logLevels: [
{ value: 'all', label: '全部' },
{ value: 'info', label: '信息' },
{ value: 'success', label: '成功' },
{ value: 'warning', label: '警告' },
{ value: 'danger', label: '错误' }
],
siteDialog: {
visible: false,
title: '添加网站',
form: {
id: null,
name: '',
domain: '',
port: 80,
ssl: false,
collapsed: false
},
editIndex: null
},
routeDialog: {
visible: false,
title: '添加路由',
form: {
path: '',
type: 'static',
target: ''
},
siteIndex: null,
editIndex: null
},
requestChart: null,
goroutineChart: null,
chartInterval: null
}
},
computed: {
filteredLogs() {
let result = this.logs;
if (this.filterType !== 'all') {
result = result.filter(log => log.type === this.filterType);
}
if (this.searchQuery) {
const query = this.searchQuery.toLowerCase();
result = result.filter(log =>
log.message.toLowerCase().includes(query) ||
log.timestamp.includes(query)
);
}
return result;
}
},
mounted() {
this.requestCount = Math.floor(Math.random() * 1000) + 500;
// 模拟数据更新
setInterval(() => {
this.requestCount += Math.floor(Math.random() * 10);
this.goroutineCount = Math.max(5, this.goroutineCount + Math.floor(Math.random() * 5) - 2);
}, 3000);
// 应用已保存的主题
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
document.body.className = savedTheme;
}
// 初始化图表
this.initCharts();
},
beforeDestroy() {
if (this.chartInterval) {
clearInterval(this.chartInterval);
}
},
methods: {
// 站点配置管理
toggleCollapse(index) {
this.serverConfig.sites[index].collapsed = !this.serverConfig.sites[index].collapsed;
this.saveConfig();
},
saveConfig() {
localStorage.setItem('serverConfig', JSON.stringify(this.serverConfig));
this.logAction('保存了服务器配置', 'success');
},
addSite() {
this.siteDialog = {
visible: true,
title: '添加网站',
form: {
id: Date.now(),
name: '新网站',
domain: 'new-site.com',
port: 80,
ssl: false,
collapsed: false
},
editIndex: null
};
},
editSite(index) {
const site = this.serverConfig.sites[index];
this.siteDialog = {
visible: true,
title: '编辑网站',
form: JSON.parse(JSON.stringify(site)),
editIndex: index
};
},
saveSite() {
if (this.siteDialog.editIndex !== null) {
this.serverConfig.sites.splice(this.siteDialog.editIndex, 1, this.siteDialog.form);
this.logAction(`更新了网站 ${this.siteDialog.form.name} 的配置`, 'success');
} else {
this.serverConfig.sites.push({
...this.siteDialog.form,
routes: []
});
this.logAction(`添加了网站 ${this.siteDialog.form.name}`, 'success');
}
this.saveConfig();
this.siteDialog.visible = false;
},
deleteSite(index) {
this.$confirm('确定要删除这个网站吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const site = this.serverConfig.sites[index];
this.serverConfig.sites.splice(index, 1);
this.saveConfig();
this.logAction(`删除了网站 ${site.name}`, 'warning');
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
// 路由管理
addRoute(siteIndex) {
this.routeDialog = {
visible: true,
title: '添加路由',
form: {
path: '',
type: 'static',
target: ''
},
siteIndex,
editIndex: null
};
},
editRoute(siteIndex, routeIndex) {
const route = this.serverConfig.sites[siteIndex].routes[routeIndex];
this.routeDialog = {
visible: true,
title: '编辑路由',
form: JSON.parse(JSON.stringify(route)),
siteIndex,
editIndex: routeIndex
};
},
saveRoute() {
const site = this.serverConfig.sites[this.routeDialog.siteIndex];
if (this.routeDialog.editIndex !== null) {
site.routes.splice(this.routeDialog.editIndex, 1, this.routeDialog.form);
this.logAction(`更新了路由 ${this.routeDialog.form.path}`, 'success');
} else {
site.routes.push(this.routeDialog.form);
this.logAction(`添加了路由 ${this.routeDialog.form.path}`, 'success');
}
this.saveConfig();
this.routeDialog.visible = false;
},
deleteRoute(siteIndex, routeIndex) {
this.$confirm('确定要删除这个路由吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const route = this.serverConfig.sites[siteIndex].routes[routeIndex];
this.serverConfig.sites[siteIndex].routes.splice(routeIndex, 1);
this.saveConfig();
this.logAction(`删除了路由 ${route.path}`, 'warning');
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
// 配置导入导出
exportConfig() {
const dataStr = JSON.stringify(this.serverConfig, null, 2);
const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
const exportFileDefaultName = `server-config-${new Date().toISOString().slice(0,10)}.json`;
const linkElement = document.createElement('a');
linkElement.setAttribute('href', dataUri);
linkElement.setAttribute('download', exportFileDefaultName);
linkElement.click();
this.logAction('导出了服务器配置', 'success');
},
importConfig() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = e => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = event => {
try {
const importedConfig = JSON.parse(event.target.result);
this.$confirm('确定要导入此配置吗?当前配置将被覆盖。', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.serverConfig = importedConfig;
this.saveConfig();
this.logAction('导入了服务器配置', 'success');
this.$message({
type: 'success',
message: '导入成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消导入'
});
});
} catch (error) {
this.$message.error('配置文件格式错误: ' + error.message);
}
};
reader.readAsText(file);
};
input.click();
},
// 日志管理
logAction(message, type = 'info') {
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
this.logs.unshift({ timestamp, message, type });
if (this.logs.length > 100) {
this.logs = this.logs.slice(0, 100);
}
localStorage.setItem('serverLogs', JSON.stringify(this.logs));
},
clearLogs() {
this.$confirm('确定要清空所有操作日志吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.logs = [];
localStorage.setItem('serverLogs', JSON.stringify(this.logs));
this.logAction('清空了所有操作日志', 'warning');
this.$message.success('日志已清空');
}).catch(() => {
this.$message.info('已取消清空操作');
});
},
exportLogs() {
const dataStr = JSON.stringify(this.logs, null, 2);
const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
const exportFileDefaultName = `server-logs-${new Date().toISOString().slice(0,10)}.json`;
const linkElement = document.createElement('a');
linkElement.setAttribute('href', dataUri);
linkElement.setAttribute('download', exportFileDefaultName);
linkElement.click();
this.logAction('导出了操作日志', 'info');
},
getTypeColor(type) {
const colors = {
info: 'text-blue-400',
success: 'text-green-400',
warning: 'text-yellow-400',
danger: 'text-red-400'
};
return colors[type] || 'text-gray-400';
},
// 主题管理
changeTheme(theme) {
document.body.className = theme;
localStorage.setItem('theme', theme);
// 更新图表颜色以匹配主题
this.updateChartColors(theme);
let themeName = '未知';
switch (theme) {
case 'theme-dark':
themeName = '暗色';
break;
case 'theme-light':
themeName = '亮色';
break;
case 'theme-tech':
themeName = '科技';
break;
}
this.logAction(`切换为${themeName}主题`, 'info');
},
// 服务器控制
startServer() {
this.logAction('启动了HTTP服务器', 'success');
this.$message.success('服务器已启动');
},
stopServer() {
this.logAction('停止了HTTP服务器', 'warning');
this.$message.warning('服务器已停止');
},
restartServer() {
this.logAction('重启了HTTP服务器', 'info');
this.$message.info('服务器正在重启');
},
showLogs() {
this.$message.info('正在显示日志');
},
// 图表功能
initCharts() {
// 初始化请求图表
const requestCtx = document.getElementById('request-chart').getContext('2d');
this.requestChart = new Chart(requestCtx, {
type: 'line',
data: {
labels: Array.from({length: 12}, (_, i) => `${i*5}`),
datasets: [{
label: '访问量',
data: Array.from({length: 12}, () => Math.floor(Math.random() * 100) + 50),
borderColor: 'rgba(58, 134, 255, 0.8)',
backgroundColor: 'rgba(58, 134, 255, 0.1)',
borderWidth: 2,
tension: 0.4,
fill: true,
pointRadius: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
x: {
display: false,
grid: {
display: false
}
},
y: {
display: false,
grid: {
display: false
}
}
}
}
});
// 初始化Goroutine图表
const goroutineCtx = document.getElementById('goroutine-chart').getContext('2d');
this.goroutineChart = new Chart(goroutineCtx, {
type: 'line',
data: {
labels: Array.from({length: 12}, (_, i) => `${i*5}`),
datasets: [{
label: 'Goroutines',
data: Array.from({length: 12}, () => Math.floor(Math.random() * 20) + 10),
borderColor: 'rgba(131, 56, 236, 0.8)',
backgroundColor: 'rgba(131, 56, 236, 0.1)',
borderWidth: 2,
tension: 0.4,
fill: true,
pointRadius: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
x: {
display: false,
grid: {
display: false
}
},
y: {
display: false,
grid: {
display: false
}
}
}
}
});
// 模拟实时数据更新
this.chartInterval = setInterval(() => {
// 更新请求图表数据
const requestData = this.requestChart.data.datasets[0].data;
requestData.shift();
requestData.push(Math.floor(Math.random() * 30) + requestData[requestData.length - 1] - 15);
this.requestChart.update();
// 更新Goroutine图表数据
const goroutineData = this.goroutineChart.data.datasets[0].data;
goroutineData.shift();
goroutineData.push(Math.floor(Math.random() * 5) + goroutineData[goroutineData.length - 1] - 2);
this.goroutineChart.update();
}, 5000);
},
updateChartColors(theme) {
let requestColor, goroutineColor;
switch(theme) {
case 'theme-tech':
requestColor = 'rgba(0, 247, 255, 0.8)';
goroutineColor = 'rgba(0, 200, 255, 0.8)';
break;
case 'theme-light':
requestColor = 'rgba(0, 102, 255, 0.8)';
goroutineColor = 'rgba(98, 0, 238, 0.8)';
break;
default: // dark theme
requestColor = 'rgba(58, 134, 255, 0.8)';
goroutineColor = 'rgba(131, 56, 236, 0.8)';
}
if (this.requestChart) {
this.requestChart.data.datasets[0].borderColor = requestColor;
this.requestChart.data.datasets[0].backgroundColor = requestColor.replace('0.8', '0.1');
this.requestChart.update();
}
if (this.goroutineChart) {
this.goroutineChart.data.datasets[0].borderColor = goroutineColor;
this.goroutineChart.data.datasets[0].backgroundColor = goroutineColor.replace('0.8', '0.1');
this.goroutineChart.update();
}
}
}
});